Skip to content

Commit 484f2f3

Browse files
Copilotlstein
andcommitted
Add Confirm Password field to My Profile password change form
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
1 parent a043d77 commit 484f2f3

3 files changed

Lines changed: 259 additions & 124 deletions

File tree

invokeai/frontend/web/public/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
"currentPasswordPlaceholder": "Current password",
6565
"newPassword": "New Password",
6666
"newPasswordPlaceholder": "New password",
67+
"confirmPassword": "Confirm New Password",
68+
"confirmPasswordPlaceholder": "Confirm new password",
69+
"passwordsDoNotMatch": "Passwords do not match",
6770
"saveSuccess": "Profile updated successfully",
6871
"saveFailed": "Failed to save profile. Please try again."
6972
},

invokeai/frontend/web/src/features/auth/components/UserManagement.tsx

Lines changed: 96 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
FormControl,
99
FormErrorMessage,
1010
FormLabel,
11+
Grid,
12+
GridItem,
1113
Heading,
1214
IconButton,
1315
Input,
@@ -38,7 +40,15 @@ import { selectCurrentUser } from 'features/auth/store/authSlice';
3840
import type { ChangeEvent, FormEvent } from 'react';
3941
import { memo, useCallback, useState } from 'react';
4042
import { useTranslation } from 'react-i18next';
41-
import { PiArrowLeftBold, PiEyeBold, PiEyeSlashBold, PiPencilBold, PiPlusBold, PiTrashBold } from 'react-icons/pi';
43+
import {
44+
PiArrowLeftBold,
45+
PiEyeBold,
46+
PiEyeSlashBold,
47+
PiLightningFill,
48+
PiPencilBold,
49+
PiPlusBold,
50+
PiTrashBold,
51+
} from 'react-icons/pi';
4252
import { useNavigate } from 'react-router-dom';
4353
import type { UserDTO } from 'services/api/endpoints/auth';
4454
import {
@@ -68,6 +78,8 @@ const validatePasswordStrength = (
6878
return { isValid: true, message: '' };
6979
};
7080

81+
const FORM_GRID_COLUMNS = '120px 1fr';
82+
7183
// ---------------------------------------------------------------------------
7284
// Create / Edit user modal
7385
// ---------------------------------------------------------------------------
@@ -206,71 +218,100 @@ const UserFormModal = memo(({ isOpen, onClose, editUser }: UserFormModalProps) =
206218
<VStack spacing={4}>
207219
{!isEdit && (
208220
<FormControl isRequired>
209-
<FormLabel>{t('auth.userManagement.email')}</FormLabel>
210-
<Input
211-
type="email"
212-
value={email}
213-
onChange={handleEmailChange}
214-
placeholder={t('auth.userManagement.emailPlaceholder')}
215-
autoComplete="off"
216-
/>
221+
<Grid templateColumns={FORM_GRID_COLUMNS} gap={4} alignItems="start">
222+
<GridItem>
223+
<FormLabel textAlign="right" mb={0} pt={2}>
224+
{t('auth.userManagement.email')}
225+
</FormLabel>
226+
</GridItem>
227+
<GridItem>
228+
<Input
229+
type="email"
230+
value={email}
231+
onChange={handleEmailChange}
232+
placeholder={t('auth.userManagement.emailPlaceholder')}
233+
autoComplete="off"
234+
/>
235+
</GridItem>
236+
</Grid>
217237
</FormControl>
218238
)}
219239

220240
<FormControl>
221-
<FormLabel>{t('auth.userManagement.displayName')}</FormLabel>
222-
<Input
223-
type="text"
224-
value={displayName}
225-
onChange={handleDisplayNameChange}
226-
placeholder={t('auth.userManagement.displayNamePlaceholder')}
227-
/>
241+
<Grid templateColumns={FORM_GRID_COLUMNS} gap={4} alignItems="start">
242+
<GridItem>
243+
<FormLabel textAlign="right" mb={0} pt={2}>
244+
{t('auth.userManagement.displayName')}
245+
</FormLabel>
246+
</GridItem>
247+
<GridItem>
248+
<Input
249+
type="text"
250+
value={displayName}
251+
onChange={handleDisplayNameChange}
252+
placeholder={t('auth.userManagement.displayNamePlaceholder')}
253+
/>
254+
</GridItem>
255+
</Grid>
228256
</FormControl>
229257

230258
<FormControl isInvalid={password.length > 0 && !passwordValidation.isValid} isRequired={!isEdit}>
231-
<FormLabel>
232-
{isEdit ? t('auth.userManagement.newPassword') : t('auth.userManagement.password')}
233-
</FormLabel>
234-
<InputGroup>
235-
<Input
236-
type={showPassword ? 'text' : 'password'}
237-
value={password}
238-
onChange={handlePasswordChange}
239-
placeholder={
240-
isEdit
241-
? t('auth.userManagement.newPasswordPlaceholder')
242-
: t('auth.userManagement.passwordPlaceholder')
243-
}
244-
autoComplete="new-password"
245-
pr="4.5rem"
246-
/>
247-
<InputRightElement w="4.5rem">
248-
<Tooltip
249-
label={
250-
showPassword ? t('auth.userManagement.hidePassword') : t('auth.userManagement.showPassword')
251-
}
252-
>
253-
<IconButton
254-
aria-label={
255-
showPassword ? t('auth.userManagement.hidePassword') : t('auth.userManagement.showPassword')
259+
<Grid templateColumns={FORM_GRID_COLUMNS} gap={4} alignItems="start">
260+
<GridItem>
261+
<FormLabel textAlign="right" mb={0} pt={2}>
262+
{isEdit ? t('auth.userManagement.newPassword') : t('auth.userManagement.password')}
263+
</FormLabel>
264+
</GridItem>
265+
<GridItem>
266+
<InputGroup>
267+
<Input
268+
type={showPassword ? 'text' : 'password'}
269+
value={password}
270+
onChange={handlePasswordChange}
271+
placeholder={
272+
isEdit
273+
? t('auth.userManagement.newPasswordPlaceholder')
274+
: t('auth.userManagement.passwordPlaceholder')
256275
}
257-
icon={showPassword ? <PiEyeSlashBold /> : <PiEyeBold />}
258-
variant="ghost"
259-
size="sm"
260-
onClick={toggleShowPassword}
261-
tabIndex={-1}
276+
autoComplete="new-password"
277+
pr="4.5rem"
262278
/>
263-
</Tooltip>
264-
</InputRightElement>
265-
</InputGroup>
266-
{password.length > 0 && !passwordValidation.isValid && (
267-
<FormErrorMessage>{passwordValidation.message}</FormErrorMessage>
268-
)}
279+
<InputRightElement w="4.5rem">
280+
<Tooltip
281+
label={
282+
showPassword ? t('auth.userManagement.hidePassword') : t('auth.userManagement.showPassword')
283+
}
284+
>
285+
<IconButton
286+
aria-label={
287+
showPassword
288+
? t('auth.userManagement.hidePassword')
289+
: t('auth.userManagement.showPassword')
290+
}
291+
icon={showPassword ? <PiEyeSlashBold /> : <PiEyeBold />}
292+
variant="ghost"
293+
size="sm"
294+
onClick={toggleShowPassword}
295+
tabIndex={-1}
296+
/>
297+
</Tooltip>
298+
</InputRightElement>
299+
</InputGroup>
300+
{password.length > 0 && !passwordValidation.isValid && (
301+
<FormErrorMessage>{passwordValidation.message}</FormErrorMessage>
302+
)}
303+
</GridItem>
304+
</Grid>
269305
</FormControl>
270306

271-
<Button size="sm" variant="ghost" onClick={handleGeneratePassword} alignSelf="flex-start">
272-
{t('auth.userManagement.generatePassword')}
273-
</Button>
307+
<Grid templateColumns={FORM_GRID_COLUMNS} gap={4} w="full">
308+
<GridItem />
309+
<GridItem>
310+
<Button size="sm" variant="ghost" onClick={handleGeneratePassword} leftIcon={<PiLightningFill />}>
311+
{t('auth.userManagement.generatePassword')}
312+
</Button>
313+
</GridItem>
314+
</Grid>
274315

275316
<FormControl display="flex" alignItems="center">
276317
<FormLabel mb={0}>{t('auth.userManagement.isAdmin')}</FormLabel>

0 commit comments

Comments
 (0)