mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 13:22:14 +00:00
Name the admin account and invite cards apart from their pages
The users page card is now "Accounts" and the invites card "Invite links", so neither repeats the page title above it, and the token overview reads "API tokens" in sentence case. The role filter pills stay neutral when selected, and the three icon tools on a phone row wrap as one group instead of leaving the sign-out icon on its own line.
This commit is contained in:
1 parent
161963c82b
commit
c90d28e597
9 files changed
+78
-71
No files matched your search
+4
-4
@@ -7377,8 +7377,8 @@
|
||||
"coachFollowsSwitch": "Folgt dem Coach-Schalter im Bereich Coach."
|
||||
},
|
||||
"invites": {
|
||||
"title": "Einladungen",
|
||||
"description": "Einladungslinks für die Registrierung — funktionieren auch bei geschlossener Registrierung.",
|
||||
"title": "Einladungslinks",
|
||||
"description": "Jeder Link lässt eine Registrierung zu, auch wenn sie geschlossen ist.",
|
||||
"create": "Einladung erstellen",
|
||||
"createTitle": "Einladung erstellen",
|
||||
"createDescription": "Der Link erlaubt eine Registrierung auch bei geschlossener Registrierung.",
|
||||
@@ -7424,8 +7424,8 @@
|
||||
"revokedToast": "Einladung widerrufen.",
|
||||
"revokeError": "Einladung konnte nicht widerrufen werden."
|
||||
},
|
||||
"userManagement": "Nutzerverwaltung",
|
||||
"userManagementDescription": "Konten verwalten: Rollen, Passwort-Resets und erzwungene Abmeldungen.",
|
||||
"userManagement": "Konten",
|
||||
"userManagementDescription": "Rollen, Passwort-Resets und erzwungene Abmeldungen für jedes Konto.",
|
||||
"userName": "Name",
|
||||
"userEmail": "E-Mail",
|
||||
"userRole": "Rolle",
|
||||
|
||||
+5
-5
@@ -7377,8 +7377,8 @@
|
||||
"coachFollowsSwitch": "Follows the Coach switch in the Coach section."
|
||||
},
|
||||
"invites": {
|
||||
"title": "Invites",
|
||||
"description": "Registration invite links — they work even while registration is closed.",
|
||||
"title": "Invite links",
|
||||
"description": "Each link admits a signup even while registration is closed.",
|
||||
"create": "Create invite",
|
||||
"createTitle": "Create invite",
|
||||
"createDescription": "The link admits a signup even while registration is closed.",
|
||||
@@ -7424,8 +7424,8 @@
|
||||
"revokedToast": "Invite revoked.",
|
||||
"revokeError": "Could not revoke the invite."
|
||||
},
|
||||
"userManagement": "User Management",
|
||||
"userManagementDescription": "Manage accounts: roles, password resets, and forced logouts.",
|
||||
"userManagement": "Accounts",
|
||||
"userManagementDescription": "Roles, password resets and forced logouts for every account.",
|
||||
"userName": "Name",
|
||||
"userEmail": "Email",
|
||||
"userRole": "Role",
|
||||
@@ -7446,7 +7446,7 @@
|
||||
"passwordReset": "Password has been reset",
|
||||
"reset": "Reset",
|
||||
"loadingUsers": "Loading users…",
|
||||
"apiTokens": "API Tokens",
|
||||
"apiTokens": "API tokens",
|
||||
"apiTokensDescription": "All active and revoked API tokens across all accounts.",
|
||||
"tokenUser": "User",
|
||||
"tokenName": "Name",
|
||||
|
||||
+4
-4
@@ -7377,8 +7377,8 @@
|
||||
"coachFollowsSwitch": "Sigue el interruptor del Coach en la sección Coach."
|
||||
},
|
||||
"invites": {
|
||||
"title": "Invitaciones",
|
||||
"description": "Enlaces de invitación para el registro: funcionan incluso con el registro cerrado.",
|
||||
"title": "Enlaces de invitación",
|
||||
"description": "Cada enlace permite un registro aunque el registro esté cerrado.",
|
||||
"create": "Crear invitación",
|
||||
"createTitle": "Crear invitación",
|
||||
"createDescription": "El enlace permite registrarse incluso con el registro cerrado.",
|
||||
@@ -7424,8 +7424,8 @@
|
||||
"revokedToast": "Invitación revocada.",
|
||||
"revokeError": "No se pudo revocar la invitación."
|
||||
},
|
||||
"userManagement": "Gestión de usuarios",
|
||||
"userManagementDescription": "Gestiona las cuentas: roles, restablecimientos de contraseña y cierres de sesión forzados.",
|
||||
"userManagement": "Cuentas",
|
||||
"userManagementDescription": "Roles, restablecimientos de contraseña y cierres de sesión forzados de cada cuenta.",
|
||||
"userName": "Nombre",
|
||||
"userEmail": "Correo electrónico",
|
||||
"userRole": "Rol",
|
||||
|
||||
+4
-4
@@ -7377,8 +7377,8 @@
|
||||
"coachFollowsSwitch": "Suit l'interrupteur Coach de la section Coach."
|
||||
},
|
||||
"invites": {
|
||||
"title": "Invitations",
|
||||
"description": "Liens d'invitation pour l'inscription — ils fonctionnent même lorsque les inscriptions sont fermées.",
|
||||
"title": "Liens d'invitation",
|
||||
"description": "Chaque lien permet une inscription même lorsque les inscriptions sont fermées.",
|
||||
"create": "Créer une invitation",
|
||||
"createTitle": "Créer une invitation",
|
||||
"createDescription": "Le lien permet une inscription même lorsque les inscriptions sont fermées.",
|
||||
@@ -7424,8 +7424,8 @@
|
||||
"revokedToast": "Invitation révoquée.",
|
||||
"revokeError": "Impossible de révoquer l'invitation."
|
||||
},
|
||||
"userManagement": "Gestion des utilisateurs",
|
||||
"userManagementDescription": "Gérez les comptes : rôles, réinitialisations de mot de passe et déconnexions forcées.",
|
||||
"userManagement": "Comptes",
|
||||
"userManagementDescription": "Rôles, réinitialisations de mot de passe et déconnexions forcées pour chaque compte.",
|
||||
"userName": "Nom",
|
||||
"userEmail": "E-mail",
|
||||
"userRole": "Rôle",
|
||||
|
||||
+4
-4
@@ -7377,8 +7377,8 @@
|
||||
"coachFollowsSwitch": "Segue l'interruttore Coach nella sezione Coach."
|
||||
},
|
||||
"invites": {
|
||||
"title": "Inviti",
|
||||
"description": "Link di invito per la registrazione: funzionano anche quando la registrazione è chiusa.",
|
||||
"title": "Link di invito",
|
||||
"description": "Ogni link consente una registrazione anche quando la registrazione è chiusa.",
|
||||
"create": "Crea invito",
|
||||
"createTitle": "Crea invito",
|
||||
"createDescription": "Il link consente una registrazione anche quando la registrazione è chiusa.",
|
||||
@@ -7424,8 +7424,8 @@
|
||||
"revokedToast": "Invito revocato.",
|
||||
"revokeError": "Impossibile revocare l'invito."
|
||||
},
|
||||
"userManagement": "Gestione utenti",
|
||||
"userManagementDescription": "Gestisci gli account: ruoli, reset delle password e disconnessioni forzate.",
|
||||
"userManagement": "Account",
|
||||
"userManagementDescription": "Ruoli, reset delle password e disconnessioni forzate per ogni account.",
|
||||
"userName": "Nome",
|
||||
"userEmail": "E-mail",
|
||||
"userRole": "Ruolo",
|
||||
|
||||
+4
-4
@@ -7353,8 +7353,8 @@
|
||||
"coachFollowsSwitch": "코치 섹션의 코치 스위치를 따라요."
|
||||
},
|
||||
"invites": {
|
||||
"title": "초대",
|
||||
"description": "가입 초대 링크 — 회원가입이 닫혀 있어도 동작해요.",
|
||||
"title": "초대 링크",
|
||||
"description": "링크마다 회원가입이 닫혀 있어도 가입할 수 있어요.",
|
||||
"create": "초대 만들기",
|
||||
"createTitle": "초대 만들기",
|
||||
"createDescription": "회원가입이 닫혀 있어도 이 링크로는 가입할 수 있어요.",
|
||||
@@ -7400,8 +7400,8 @@
|
||||
"revokedToast": "초대를 취소했어요.",
|
||||
"revokeError": "초대를 취소하지 못했어요."
|
||||
},
|
||||
"userManagement": "사용자 관리",
|
||||
"userManagementDescription": "계정 관리: 역할, 비밀번호 재설정, 강제 로그아웃.",
|
||||
"userManagement": "계정",
|
||||
"userManagementDescription": "계정마다 역할, 비밀번호 재설정, 강제 로그아웃을 관리해요.",
|
||||
"userName": "이름",
|
||||
"userEmail": "이메일",
|
||||
"userRole": "역할",
|
||||
|
||||
+4
-4
@@ -7377,8 +7377,8 @@
|
||||
"coachFollowsSwitch": "Podlega przełącznikowi Coach w sekcji Coach."
|
||||
},
|
||||
"invites": {
|
||||
"title": "Zaproszenia",
|
||||
"description": "Linki z zaproszeniem do rejestracji — działają nawet przy zamkniętej rejestracji.",
|
||||
"title": "Linki z zaproszeniem",
|
||||
"description": "Każdy link pozwala na rejestrację nawet przy zamkniętej rejestracji.",
|
||||
"create": "Utwórz zaproszenie",
|
||||
"createTitle": "Utwórz zaproszenie",
|
||||
"createDescription": "Link umożliwia rejestrację nawet przy zamkniętej rejestracji.",
|
||||
@@ -7424,8 +7424,8 @@
|
||||
"revokedToast": "Zaproszenie unieważnione.",
|
||||
"revokeError": "Nie udało się unieważnić zaproszenia."
|
||||
},
|
||||
"userManagement": "Zarządzanie użytkownikami",
|
||||
"userManagementDescription": "Zarządzaj kontami: role, resety haseł i wymuszone wylogowania.",
|
||||
"userManagement": "Konta",
|
||||
"userManagementDescription": "Role, resety haseł i wymuszone wylogowania dla każdego konta.",
|
||||
"userName": "Nazwa",
|
||||
"userEmail": "E-mail",
|
||||
"userRole": "Rola",
|
||||
|
||||
@@ -102,7 +102,7 @@ describe("admin sections — SSR smoke", () => {
|
||||
|
||||
it("<UserManagementSection> renders with filter pills", () => {
|
||||
const html = render(<UserManagementSection />);
|
||||
expect(html).toContain("User Management");
|
||||
expect(html).toContain("Accounts");
|
||||
// Filter pills painted from i18n
|
||||
expect(html).toContain("All");
|
||||
expect(html).toContain("Admins");
|
||||
@@ -110,7 +110,7 @@ describe("admin sections — SSR smoke", () => {
|
||||
|
||||
it("<ApiTokenOverviewSection> renders", () => {
|
||||
const html = render(<ApiTokenOverviewSection />);
|
||||
expect(html).toContain("API Tokens");
|
||||
expect(html).toContain("API tokens");
|
||||
});
|
||||
|
||||
it("<LoginOverviewSection> renders", () => {
|
||||
|
||||
@@ -231,45 +231,50 @@ export function UserManagementSection() {
|
||||
<ShieldCheck className="h-3 w-3" aria-hidden="true" />
|
||||
{u.mfaEnforced ? t("admin.mfaEnforcedOn") : t("admin.mfaEnforcedOff")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="min-h-11 min-w-11 px-2 text-xs"
|
||||
onClick={() => startEdit(u)}
|
||||
title={t("admin.editUser")}
|
||||
aria-label={t("admin.editUser")}
|
||||
>
|
||||
<Pencil className="h-3 w-3" aria-hidden="true" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="min-h-11 min-w-11 px-2 text-xs"
|
||||
onClick={() => startReset(u)}
|
||||
title={t("admin.resetPassword")}
|
||||
aria-label={t("admin.resetPassword")}
|
||||
>
|
||||
<KeyRound className="h-3 w-3" aria-hidden="true" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-muted-foreground hover:text-foreground min-h-11 min-w-11 px-2 text-xs"
|
||||
onClick={() => setLogoutTarget(u)}
|
||||
disabled={u.id === currentUserId}
|
||||
title={
|
||||
u.id === currentUserId
|
||||
? t("admin.section.users.cannotLogoutSelf")
|
||||
: t("admin.section.users.forceLogout")
|
||||
}
|
||||
aria-label={
|
||||
u.id === currentUserId
|
||||
? t("admin.section.users.cannotLogoutSelf")
|
||||
: t("admin.section.users.forceLogout")
|
||||
}
|
||||
>
|
||||
<LogOut className="h-3 w-3" aria-hidden="true" />
|
||||
</Button>
|
||||
{/* The three icon tools travel as one group: on a phone the row wraps
|
||||
between the labelled toggles and the tools, never leaving the
|
||||
sign-out icon alone on a line. */}
|
||||
<span className="ml-auto flex items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="min-h-11 min-w-11 px-2 text-xs"
|
||||
onClick={() => startEdit(u)}
|
||||
title={t("admin.editUser")}
|
||||
aria-label={t("admin.editUser")}
|
||||
>
|
||||
<Pencil className="h-3 w-3" aria-hidden="true" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="min-h-11 min-w-11 px-2 text-xs"
|
||||
onClick={() => startReset(u)}
|
||||
title={t("admin.resetPassword")}
|
||||
aria-label={t("admin.resetPassword")}
|
||||
>
|
||||
<KeyRound className="h-3 w-3" aria-hidden="true" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-muted-foreground hover:text-foreground min-h-11 min-w-11 px-2 text-xs"
|
||||
onClick={() => setLogoutTarget(u)}
|
||||
disabled={u.id === currentUserId}
|
||||
title={
|
||||
u.id === currentUserId
|
||||
? t("admin.section.users.cannotLogoutSelf")
|
||||
: t("admin.section.users.forceLogout")
|
||||
}
|
||||
aria-label={
|
||||
u.id === currentUserId
|
||||
? t("admin.section.users.cannotLogoutSelf")
|
||||
: t("admin.section.users.forceLogout")
|
||||
}
|
||||
>
|
||||
<LogOut className="h-3 w-3" aria-hidden="true" />
|
||||
</Button>
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -306,7 +311,9 @@ export function UserManagementSection() {
|
||||
{(["all", "admin", "user"] as const).map((value) => (
|
||||
<Button
|
||||
key={value}
|
||||
variant={filter === value ? "default" : "outline"}
|
||||
// Neutral pills: the selected filter is a state, not a call to
|
||||
// action, so it never takes the primary fill.
|
||||
variant={filter === value ? "secondary" : "outline"}
|
||||
size="sm"
|
||||
className="min-h-11 min-w-11 px-3 text-xs sm:min-h-9"
|
||||
onClick={() => setFilter(value)}
|
||||
|
||||
Reference in new issue
Block a user