mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Login: Show additional information when prompting to change password (#69537)
* add some information to the password change screen * update threshold cause pa11y is stupid * override the loginlayout title if changing password * remove top padding from inner box
This commit is contained in:
parent
c1d3a2d81e
commit
48e328c1dd
@ -74,7 +74,7 @@ var config = {
|
|||||||
"click element button[aria-label='Login button']",
|
"click element button[aria-label='Login button']",
|
||||||
"wait for element [aria-label='Skip change password button'] to be visible",
|
"wait for element [aria-label='Skip change password button'] to be visible",
|
||||||
],
|
],
|
||||||
threshold: 14,
|
threshold: 15,
|
||||||
rootElement: '.main-view',
|
rootElement: '.main-view',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import React, { SyntheticEvent } from 'react';
|
import React, { SyntheticEvent } from 'react';
|
||||||
|
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Tooltip, Form, Field, VerticalGroup, Button } from '@grafana/ui';
|
import { Tooltip, Form, Field, VerticalGroup, Button, Alert } from '@grafana/ui';
|
||||||
|
|
||||||
import { submitButton } from '../Login/LoginForm';
|
import { submitButton } from '../Login/LoginForm';
|
||||||
import { PasswordField } from '../PasswordField/PasswordField';
|
import { PasswordField } from '../PasswordField/PasswordField';
|
||||||
interface Props {
|
interface Props {
|
||||||
onSubmit: (pw: string) => void;
|
onSubmit: (pw: string) => void;
|
||||||
onSkip?: (event?: SyntheticEvent) => void;
|
onSkip?: (event?: SyntheticEvent) => void;
|
||||||
|
showDefaultPasswordWarning?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PasswordDTO {
|
interface PasswordDTO {
|
||||||
@ -15,7 +16,7 @@ interface PasswordDTO {
|
|||||||
confirmNew: string;
|
confirmNew: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChangePassword = ({ onSubmit, onSkip }: Props) => {
|
export const ChangePassword = ({ onSubmit, onSkip, showDefaultPasswordWarning }: Props) => {
|
||||||
const submit = (passwords: PasswordDTO) => {
|
const submit = (passwords: PasswordDTO) => {
|
||||||
onSubmit(passwords.newPassword);
|
onSubmit(passwords.newPassword);
|
||||||
};
|
};
|
||||||
@ -23,6 +24,9 @@ export const ChangePassword = ({ onSubmit, onSkip }: Props) => {
|
|||||||
<Form onSubmit={submit}>
|
<Form onSubmit={submit}>
|
||||||
{({ errors, register, getValues }) => (
|
{({ errors, register, getValues }) => (
|
||||||
<>
|
<>
|
||||||
|
{showDefaultPasswordWarning && (
|
||||||
|
<Alert severity="info" title="Continuing to use the default password exposes you to security risks." />
|
||||||
|
)}
|
||||||
<Field label="New password" invalid={!!errors.newPassword} error={errors?.newPassword?.message}>
|
<Field label="New password" invalid={!!errors.newPassword} error={errors?.newPassword?.message}>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
id="new-password"
|
id="new-password"
|
||||||
|
@ -11,7 +11,7 @@ export interface Props extends GrafanaRouteComponentProps<{}, { code: string }>
|
|||||||
|
|
||||||
export const ChangePasswordPage = (props: Props) => {
|
export const ChangePasswordPage = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<LoginLayout>
|
<LoginLayout isChangingPassword>
|
||||||
<InnerBox>
|
<InnerBox>
|
||||||
<LoginCtrl resetCode={props.queryParams.code}>
|
<LoginCtrl resetCode={props.queryParams.code}>
|
||||||
{({ changePassword }) => <ChangePassword onSubmit={changePassword} />}
|
{({ changePassword }) => <ChangePassword onSubmit={changePassword} />}
|
||||||
|
@ -31,12 +31,14 @@ interface Props {
|
|||||||
isOauthEnabled: boolean;
|
isOauthEnabled: boolean;
|
||||||
loginHint: string;
|
loginHint: string;
|
||||||
passwordHint: string;
|
passwordHint: string;
|
||||||
|
showDefaultPasswordWarning: boolean;
|
||||||
}) => JSX.Element;
|
}) => JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
isLoggingIn: boolean;
|
isLoggingIn: boolean;
|
||||||
isChangingPassword: boolean;
|
isChangingPassword: boolean;
|
||||||
|
showDefaultPasswordWarning: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LoginCtrl extends PureComponent<Props, State> {
|
export class LoginCtrl extends PureComponent<Props, State> {
|
||||||
@ -47,6 +49,7 @@ export class LoginCtrl extends PureComponent<Props, State> {
|
|||||||
this.state = {
|
this.state = {
|
||||||
isLoggingIn: false,
|
isLoggingIn: false,
|
||||||
isChangingPassword: false,
|
isChangingPassword: false,
|
||||||
|
showDefaultPasswordWarning: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.loginError) {
|
if (config.loginError) {
|
||||||
@ -96,7 +99,7 @@ export class LoginCtrl extends PureComponent<Props, State> {
|
|||||||
this.toGrafana();
|
this.toGrafana();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this.changeView();
|
this.changeView(formModel.password === 'admin');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -106,9 +109,10 @@ export class LoginCtrl extends PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
changeView = () => {
|
changeView = (showDefaultPasswordWarning: boolean) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isChangingPassword: true,
|
isChangingPassword: true,
|
||||||
|
showDefaultPasswordWarning,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -127,7 +131,7 @@ export class LoginCtrl extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
const { isLoggingIn, isChangingPassword } = this.state;
|
const { isLoggingIn, isChangingPassword, showDefaultPasswordWarning } = this.state;
|
||||||
const { login, toGrafana, changePassword } = this;
|
const { login, toGrafana, changePassword } = this;
|
||||||
const { loginHint, passwordHint, disableLoginForm, disableUserSignUp } = config;
|
const { loginHint, passwordHint, disableLoginForm, disableUserSignUp } = config;
|
||||||
|
|
||||||
@ -144,6 +148,7 @@ export class LoginCtrl extends PureComponent<Props, State> {
|
|||||||
changePassword,
|
changePassword,
|
||||||
skipPasswordChange: toGrafana,
|
skipPasswordChange: toGrafana,
|
||||||
isChangingPassword,
|
isChangingPassword,
|
||||||
|
showDefaultPasswordWarning,
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -19,9 +19,10 @@ export const InnerBox = ({ children, enterAnimation = true }: React.PropsWithChi
|
|||||||
export interface LoginLayoutProps {
|
export interface LoginLayoutProps {
|
||||||
/** Custom branding settings that can be used e.g. for previewing the Login page changes */
|
/** Custom branding settings that can be used e.g. for previewing the Login page changes */
|
||||||
branding?: BrandingSettings;
|
branding?: BrandingSettings;
|
||||||
|
isChangingPassword?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LoginLayout = ({ children, branding }: React.PropsWithChildren<LoginLayoutProps>) => {
|
export const LoginLayout = ({ children, branding, isChangingPassword }: React.PropsWithChildren<LoginLayoutProps>) => {
|
||||||
const loginStyles = useStyles2(getLoginStyles);
|
const loginStyles = useStyles2(getLoginStyles);
|
||||||
const [startAnim, setStartAnim] = useState(false);
|
const [startAnim, setStartAnim] = useState(false);
|
||||||
const subTitle = branding?.loginSubtitle ?? Branding.GetLoginSubTitle();
|
const subTitle = branding?.loginSubtitle ?? Branding.GetLoginSubTitle();
|
||||||
@ -39,8 +40,14 @@ export const LoginLayout = ({ children, branding }: React.PropsWithChildren<Logi
|
|||||||
<div className={loginStyles.loginLogoWrapper}>
|
<div className={loginStyles.loginLogoWrapper}>
|
||||||
<Branding.LoginLogo className={loginStyles.loginLogo} logo={loginLogo} />
|
<Branding.LoginLogo className={loginStyles.loginLogo} logo={loginLogo} />
|
||||||
<div className={loginStyles.titleWrapper}>
|
<div className={loginStyles.titleWrapper}>
|
||||||
<h1 className={loginStyles.mainTitle}>{loginTitle}</h1>
|
{isChangingPassword ? (
|
||||||
{subTitle && <h3 className={loginStyles.subTitle}>{subTitle}</h3>}
|
<h1 className={loginStyles.mainTitle}>Update your password</h1>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<h1 className={loginStyles.mainTitle}>{loginTitle}</h1>
|
||||||
|
{subTitle && <h3 className={loginStyles.subTitle}>{subTitle}</h3>}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={loginStyles.loginOuterBox}>{children}</div>
|
<div className={loginStyles.loginOuterBox}>{children}</div>
|
||||||
@ -144,7 +151,7 @@ export const getLoginStyles = (theme: GrafanaTheme2) => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
`,
|
`,
|
||||||
loginInnerBox: css`
|
loginInnerBox: css`
|
||||||
padding: ${theme.spacing(2)};
|
padding: ${theme.spacing(0, 2, 2, 2)};
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -23,52 +23,50 @@ const forgottenPasswordStyles = css`
|
|||||||
export const LoginPage = () => {
|
export const LoginPage = () => {
|
||||||
document.title = Branding.AppTitle;
|
document.title = Branding.AppTitle;
|
||||||
return (
|
return (
|
||||||
<LoginLayout>
|
<LoginCtrl>
|
||||||
<LoginCtrl>
|
{({
|
||||||
{({
|
loginHint,
|
||||||
loginHint,
|
passwordHint,
|
||||||
passwordHint,
|
disableLoginForm,
|
||||||
disableLoginForm,
|
disableUserSignUp,
|
||||||
disableUserSignUp,
|
login,
|
||||||
login,
|
isLoggingIn,
|
||||||
isLoggingIn,
|
changePassword,
|
||||||
changePassword,
|
skipPasswordChange,
|
||||||
skipPasswordChange,
|
isChangingPassword,
|
||||||
isChangingPassword,
|
showDefaultPasswordWarning,
|
||||||
}) => (
|
}) => (
|
||||||
<>
|
<LoginLayout isChangingPassword={isChangingPassword}>
|
||||||
{!isChangingPassword && (
|
{!isChangingPassword && (
|
||||||
<InnerBox>
|
<InnerBox>
|
||||||
{!disableLoginForm && (
|
{!disableLoginForm && (
|
||||||
<LoginForm
|
<LoginForm onSubmit={login} loginHint={loginHint} passwordHint={passwordHint} isLoggingIn={isLoggingIn}>
|
||||||
onSubmit={login}
|
<HorizontalGroup justify="flex-end">
|
||||||
loginHint={loginHint}
|
<LinkButton
|
||||||
passwordHint={passwordHint}
|
className={forgottenPasswordStyles}
|
||||||
isLoggingIn={isLoggingIn}
|
fill="text"
|
||||||
>
|
href={`${config.appSubUrl}/user/password/send-reset-email`}
|
||||||
<HorizontalGroup justify="flex-end">
|
>
|
||||||
<LinkButton
|
Forgot your password?
|
||||||
className={forgottenPasswordStyles}
|
</LinkButton>
|
||||||
fill="text"
|
</HorizontalGroup>
|
||||||
href={`${config.appSubUrl}/user/password/send-reset-email`}
|
</LoginForm>
|
||||||
>
|
)}
|
||||||
Forgot your password?
|
<LoginServiceButtons />
|
||||||
</LinkButton>
|
{!disableUserSignUp && <UserSignup />}
|
||||||
</HorizontalGroup>
|
</InnerBox>
|
||||||
</LoginForm>
|
)}
|
||||||
)}
|
{isChangingPassword && (
|
||||||
<LoginServiceButtons />
|
<InnerBox>
|
||||||
{!disableUserSignUp && <UserSignup />}
|
<ChangePassword
|
||||||
</InnerBox>
|
showDefaultPasswordWarning={showDefaultPasswordWarning}
|
||||||
)}
|
onSubmit={changePassword}
|
||||||
{isChangingPassword && (
|
onSkip={() => skipPasswordChange()}
|
||||||
<InnerBox>
|
/>
|
||||||
<ChangePassword onSubmit={changePassword} onSkip={() => skipPasswordChange()} />
|
</InnerBox>
|
||||||
</InnerBox>
|
)}
|
||||||
)}
|
</LoginLayout>
|
||||||
</>
|
)}
|
||||||
)}
|
</LoginCtrl>
|
||||||
</LoginCtrl>
|
|
||||||
</LoginLayout>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user