fix: fix unicode in roles, add password confirmation field
- RolesTab: wrap \u00b7 in JS expression {'\u00b7'} so JSX renders the middle dot correctly instead of literal backslash-u sequence
- UsersTab: add confirm password field with mismatch validation, hint text for password policy, and reset on cancel/success
- UserManagement.module.css: add .hintText style for password policy hint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -179,7 +179,7 @@ export default function RolesTab({ highlightId, onHighlightConsumed }: { highlig
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.entityMeta}>
|
||||
{role.description || '\u2014'} \u00b7{' '}
|
||||
{role.description || '\u2014'} {'\u00b7'}{' '}
|
||||
{getAssignmentCount(role)} assignments
|
||||
</div>
|
||||
<div className={styles.entityTags}>
|
||||
|
||||
@@ -156,3 +156,8 @@
|
||||
color: var(--error);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hintText {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
@@ -67,8 +67,11 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
||||
const [newDisplay, setNewDisplay] = useState('');
|
||||
const [newEmail, setNewEmail] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [newPasswordConfirm, setNewPasswordConfirm] = useState('');
|
||||
const [newProvider, setNewProvider] = useState<'local' | 'oidc'>('local');
|
||||
|
||||
const passwordMismatch = newPassword.length > 0 && newPasswordConfirm.length > 0 && newPassword !== newPasswordConfirm;
|
||||
|
||||
// Password reset state
|
||||
const [resettingPassword, setResettingPassword] = useState(false);
|
||||
const [newPw, setNewPw] = useState('');
|
||||
@@ -145,6 +148,7 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
||||
setNewDisplay('');
|
||||
setNewEmail('');
|
||||
setNewPassword('');
|
||||
setNewPasswordConfirm('');
|
||||
setNewProvider('local');
|
||||
},
|
||||
onError: (err: unknown) => {
|
||||
@@ -241,12 +245,24 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
||||
onChange={(e) => setNewEmail(e.target.value)}
|
||||
/>
|
||||
{newProvider === 'local' && (
|
||||
<Input
|
||||
placeholder="Password *"
|
||||
type="password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
/>
|
||||
<>
|
||||
<Input
|
||||
placeholder="Password *"
|
||||
type="password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
placeholder="Confirm Password *"
|
||||
type="password"
|
||||
value={newPasswordConfirm}
|
||||
onChange={(e) => setNewPasswordConfirm(e.target.value)}
|
||||
/>
|
||||
{passwordMismatch && (
|
||||
<span className={styles.errorText}>Passwords do not match</span>
|
||||
)}
|
||||
<span className={styles.hintText}>Min 12 chars, 3 of 4: uppercase, lowercase, number, special</span>
|
||||
</>
|
||||
)}
|
||||
{newProvider === 'oidc' && (
|
||||
<InfoCallout variant="amber">
|
||||
@@ -258,7 +274,7 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => setCreating(false)}
|
||||
onClick={() => { setCreating(false); setNewPasswordConfirm(''); }}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
@@ -270,7 +286,8 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
||||
disabled={
|
||||
!newUsername.trim() ||
|
||||
(newProvider === 'local' && !newPassword.trim()) ||
|
||||
duplicateUsername
|
||||
duplicateUsername ||
|
||||
passwordMismatch
|
||||
}
|
||||
>
|
||||
Create
|
||||
|
||||
Reference in New Issue
Block a user