From 6fdcc6ff189160d13c5735e9dbb6295ca7739b16 Mon Sep 17 00:00:00 2001 From: linoman <2051016+linoman@users.noreply.github.com> Date: Thu, 7 Mar 2024 09:01:17 -0600 Subject: [PATCH] Password Policy: Add validation labels to Update Password screen (#84052) * add validation labels to update the password screen * address rendering tests * update changePassword for profile screen --- .betterer.results | 3 - .../ForgottenPassword/ChangePassword.tsx | 28 ++- .../ChangePasswordPage.test.tsx | 3 + .../features/profile/ChangePasswordForm.tsx | 176 +++++++++--------- 4 files changed, 113 insertions(+), 97 deletions(-) diff --git a/.betterer.results b/.betterer.results index 3116e9fa592..ca5c0a6a24e 100644 --- a/.betterer.results +++ b/.betterer.results @@ -3991,9 +3991,6 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "2"], [0, 0, 0, "Do not use any type assertions.", "3"] ], - "public/app/features/profile/ChangePasswordForm.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"] - ], "public/app/features/query/components/QueryEditorRow.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], diff --git a/public/app/core/components/ForgottenPassword/ChangePassword.tsx b/public/app/core/components/ForgottenPassword/ChangePassword.tsx index 9f5a958d97d..845db05de95 100644 --- a/public/app/core/components/ForgottenPassword/ChangePassword.tsx +++ b/public/app/core/components/ForgottenPassword/ChangePassword.tsx @@ -1,4 +1,4 @@ -import React, { SyntheticEvent } from 'react'; +import React, { SyntheticEvent, useState } from 'react'; import { useForm } from 'react-hook-form'; import { selectors } from '@grafana/e2e-selectors'; @@ -6,6 +6,12 @@ import { Tooltip, Field, VerticalGroup, Button, Alert, useStyles2 } from '@grafa import { getStyles } from '../Login/LoginForm'; import { PasswordField } from '../PasswordField/PasswordField'; +import { + ValidationLabels, + strongPasswordValidations, + strongPasswordValidationRegister, +} from '../ValidationLabels/ValidationLabels'; + interface Props { onSubmit: (pw: string) => void; onSkip?: (event?: SyntheticEvent) => void; @@ -19,17 +25,23 @@ interface PasswordDTO { export const ChangePassword = ({ onSubmit, onSkip, showDefaultPasswordWarning }: Props) => { const styles = useStyles2(getStyles); + const [displayValidationLabels, setDisplayValidationLabels] = useState(false); + const [pristine, setPristine] = useState(true); + const { handleSubmit, register, getValues, formState: { errors }, + watch, } = useForm({ defaultValues: { newPassword: '', confirmNew: '', }, }); + + const newPassword = watch('newPassword'); const submit = (passwords: PasswordDTO) => { onSubmit(passwords.newPassword); }; @@ -40,12 +52,24 @@ export const ChangePassword = ({ onSubmit, onSkip, showDefaultPasswordWarning }: )} setDisplayValidationLabels(true)} + {...register('newPassword', { + required: 'New Password is required', + onBlur: () => setPristine(false), + validate: { strongPasswordValidationRegister }, + })} id="new-password" autoFocus autoComplete="new-password" /> + {displayValidationLabels && ( + + )} ({ licenseUrl: '', }, appSubUrl: '', + auth: { + basicAuthStrongPasswordPolicy: false, + }, }, })); diff --git a/public/app/features/profile/ChangePasswordForm.tsx b/public/app/features/profile/ChangePasswordForm.tsx index a6321d73271..a4aa7cd308a 100644 --- a/public/app/features/profile/ChangePasswordForm.tsx +++ b/public/app/features/profile/ChangePasswordForm.tsx @@ -1,7 +1,7 @@ -import { css } from '@emotion/css'; import React, { useState } from 'react'; -import { Button, Field, Form, HorizontalGroup, LinkButton } from '@grafana/ui'; +import { Button, Field, HorizontalGroup, LinkButton } from '@grafana/ui'; +import { Form } from 'app/core/components/Form/Form'; import { ValidationLabels, strongPasswordValidations, @@ -24,7 +24,6 @@ export interface Props { export const ChangePasswordForm = ({ user, onChangePassword, isSaving }: Props) => { const [displayValidationLabels, setDisplayValidationLabels] = useState(false); const [pristine, setPristine] = useState(true); - const [newPassword, setNewPassword] = useState(''); const { disableLoginForm } = config; const authSource = user.authLabels?.length && user.authLabels[0]; @@ -47,96 +46,89 @@ export const ChangePasswordForm = ({ user, onChangePassword, isSaving }: Props) } return ( -
-
- {({ register, errors, getValues }) => { - return ( - <> - - - + + {({ register, errors, getValues, watch }) => { + const newPassword = watch('newPassword'); + return ( + <> + + + - - setDisplayValidationLabels(true)} - value={newPassword} - {...register('newPassword', { - onBlur: () => setPristine(false), - onChange: (e) => setNewPassword(e.target.value), - required: t('profile.change-password.new-password-required', 'New password is required'), - validate: { - strongPasswordValidationRegister, - confirm: (v) => - v === getValues().confirmNew || - t('profile.change-password.passwords-must-match', 'Passwords must match'), - old: (v) => - v !== getValues().oldPassword || - t( - 'profile.change-password.new-password-same-as-old', - "New password can't be the same as the old one." - ), - }, - })} - /> - - {displayValidationLabels && ( - - )} - - - v === getValues().newPassword || + + setDisplayValidationLabels(true)} + {...register('newPassword', { + onBlur: () => setPristine(false), + required: t('profile.change-password.new-password-required', 'New password is required'), + validate: { + strongPasswordValidationRegister, + confirm: (v) => + v === getValues().confirmNew || t('profile.change-password.passwords-must-match', 'Passwords must match'), - })} - /> - - - - - Cancel - - - - ); - }} - -
+ old: (v) => + v !== getValues().oldPassword || + t( + 'profile.change-password.new-password-same-as-old', + "New password can't be the same as the old one." + ), + }, + })} + /> +
+ {displayValidationLabels && ( + + )} + + + v === getValues().newPassword || + t('profile.change-password.passwords-must-match', 'Passwords must match'), + })} + /> + + + + + Cancel + + + + ); + }} + ); };