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>
|
||||||
<div className={styles.entityMeta}>
|
<div className={styles.entityMeta}>
|
||||||
{role.description || '\u2014'} \u00b7{' '}
|
{role.description || '\u2014'} {'\u00b7'}{' '}
|
||||||
{getAssignmentCount(role)} assignments
|
{getAssignmentCount(role)} assignments
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.entityTags}>
|
<div className={styles.entityTags}>
|
||||||
|
|||||||
@@ -156,3 +156,8 @@
|
|||||||
color: var(--error);
|
color: var(--error);
|
||||||
font-size: 12px;
|
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 [newDisplay, setNewDisplay] = useState('');
|
||||||
const [newEmail, setNewEmail] = useState('');
|
const [newEmail, setNewEmail] = useState('');
|
||||||
const [newPassword, setNewPassword] = useState('');
|
const [newPassword, setNewPassword] = useState('');
|
||||||
|
const [newPasswordConfirm, setNewPasswordConfirm] = useState('');
|
||||||
const [newProvider, setNewProvider] = useState<'local' | 'oidc'>('local');
|
const [newProvider, setNewProvider] = useState<'local' | 'oidc'>('local');
|
||||||
|
|
||||||
|
const passwordMismatch = newPassword.length > 0 && newPasswordConfirm.length > 0 && newPassword !== newPasswordConfirm;
|
||||||
|
|
||||||
// Password reset state
|
// Password reset state
|
||||||
const [resettingPassword, setResettingPassword] = useState(false);
|
const [resettingPassword, setResettingPassword] = useState(false);
|
||||||
const [newPw, setNewPw] = useState('');
|
const [newPw, setNewPw] = useState('');
|
||||||
@@ -145,6 +148,7 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
|||||||
setNewDisplay('');
|
setNewDisplay('');
|
||||||
setNewEmail('');
|
setNewEmail('');
|
||||||
setNewPassword('');
|
setNewPassword('');
|
||||||
|
setNewPasswordConfirm('');
|
||||||
setNewProvider('local');
|
setNewProvider('local');
|
||||||
},
|
},
|
||||||
onError: (err: unknown) => {
|
onError: (err: unknown) => {
|
||||||
@@ -241,12 +245,24 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
|||||||
onChange={(e) => setNewEmail(e.target.value)}
|
onChange={(e) => setNewEmail(e.target.value)}
|
||||||
/>
|
/>
|
||||||
{newProvider === 'local' && (
|
{newProvider === 'local' && (
|
||||||
|
<>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Password *"
|
placeholder="Password *"
|
||||||
type="password"
|
type="password"
|
||||||
value={newPassword}
|
value={newPassword}
|
||||||
onChange={(e) => setNewPassword(e.target.value)}
|
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' && (
|
{newProvider === 'oidc' && (
|
||||||
<InfoCallout variant="amber">
|
<InfoCallout variant="amber">
|
||||||
@@ -258,7 +274,7 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
|||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => setCreating(false)}
|
onClick={() => { setCreating(false); setNewPasswordConfirm(''); }}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
@@ -270,7 +286,8 @@ export default function UsersTab({ highlightId, onHighlightConsumed }: { highlig
|
|||||||
disabled={
|
disabled={
|
||||||
!newUsername.trim() ||
|
!newUsername.trim() ||
|
||||||
(newProvider === 'local' && !newPassword.trim()) ||
|
(newProvider === 'local' && !newPassword.trim()) ||
|
||||||
duplicateUsername
|
duplicateUsername ||
|
||||||
|
passwordMismatch
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Create
|
Create
|
||||||
|
|||||||
Reference in New Issue
Block a user