mirror of
https://github.com/discourse/discourse.git
synced 2025-02-02 15:39:46 +08:00
UX: refactor password reset page (#30323)
This commit is contained in:
parent
af8c98217a
commit
8f26ae7b7d
|
@ -29,6 +29,7 @@ export default class PasswordResetController extends Controller.extend(
|
|||
requiresApproval = false;
|
||||
redirected = false;
|
||||
maskPassword = true;
|
||||
passwordValidationVisible = false;
|
||||
|
||||
lockImageUrl = getURL("/images/lock.svg");
|
||||
|
||||
|
@ -65,6 +66,30 @@ export default class PasswordResetController extends Controller.extend(
|
|||
return getURL(redirectTo || "/");
|
||||
}
|
||||
|
||||
@discourseComputed(
|
||||
"passwordValidation.ok",
|
||||
"passwordValidation.reason",
|
||||
"passwordValidationVisible"
|
||||
)
|
||||
showPasswordValidation(
|
||||
passwordValidationOk,
|
||||
passwordValidationReason,
|
||||
passwordValidationVisible
|
||||
) {
|
||||
return (
|
||||
passwordValidationOk ||
|
||||
(passwordValidationReason && passwordValidationVisible)
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
togglePasswordValidation() {
|
||||
this.set(
|
||||
"passwordValidationVisible",
|
||||
Boolean(this.passwordValidation.reason)
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
done(event) {
|
||||
if (wantsNewWindow(event)) {
|
||||
|
|
|
@ -2,11 +2,7 @@
|
|||
{{hide-application-sidebar}}
|
||||
{{hide-application-header-buttons "search" "login" "signup" "menu"}}
|
||||
<div class="container password-reset clearfix">
|
||||
<div class="pull-left col-image">
|
||||
<img src={{this.lockImageUrl}} class="password-reset-img" alt="" />
|
||||
</div>
|
||||
|
||||
<div class="pull-left col-form">
|
||||
<form class="change-password-form login-left-side">
|
||||
{{#if this.successMessage}}
|
||||
<p>{{this.successMessage}}</p>
|
||||
|
||||
|
@ -22,92 +18,95 @@
|
|||
{{/unless}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<form class="change-password-form">
|
||||
{{#if this.securityKeyOrSecondFactorRequired}}
|
||||
<h2>{{i18n "user.change_password.title"}}</h2>
|
||||
<p>
|
||||
{{i18n "user.change_password.verify_identity"}}
|
||||
</p>
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
<br />
|
||||
{{/if}}
|
||||
{{#if this.securityKeyOrSecondFactorRequired}}
|
||||
<h2>{{i18n "user.change_password.title"}}</h2>
|
||||
<p>
|
||||
{{i18n "user.change_password.verify_identity"}}
|
||||
</p>
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
<br />
|
||||
{{/if}}
|
||||
|
||||
{{#if this.displaySecurityKeyForm}}
|
||||
<SecurityKeyForm
|
||||
@setSecondFactorMethod={{fn
|
||||
(mut this.selectedSecondFactorMethod)
|
||||
}}
|
||||
@backupEnabled={{this.backupEnabled}}
|
||||
@totpEnabled={{this.secondFactorRequired}}
|
||||
@otherMethodAllowed={{this.otherMethodAllowed}}
|
||||
@action={{this.authenticateSecurityKey}}
|
||||
/>
|
||||
{{else}}
|
||||
<SecondFactorForm
|
||||
@secondFactorMethod={{this.selectedSecondFactorMethod}}
|
||||
@secondFactorToken={{this.secondFactorToken}}
|
||||
@backupEnabled={{this.backupEnabled}}
|
||||
@totpEnabled={{this.secondFactorRequired}}
|
||||
@isLogin={{false}}
|
||||
>
|
||||
<SecondFactorInput
|
||||
{{on
|
||||
"input"
|
||||
(with-event-value (fn (mut this.secondFactorToken)))
|
||||
}}
|
||||
@secondFactorMethod={{this.selectedSecondFactorMethod}}
|
||||
value={{this.secondFactorToken}}
|
||||
id="second-factor"
|
||||
/>
|
||||
</SecondFactorForm>
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.displaySecurityKeyForm}}
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
@label="submit"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
{{/unless}}
|
||||
{{#if this.displaySecurityKeyForm}}
|
||||
<SecurityKeyForm
|
||||
@setSecondFactorMethod={{fn (mut this.selectedSecondFactorMethod)}}
|
||||
@backupEnabled={{this.backupEnabled}}
|
||||
@totpEnabled={{this.secondFactorRequired}}
|
||||
@otherMethodAllowed={{this.otherMethodAllowed}}
|
||||
@action={{this.authenticateSecurityKey}}
|
||||
/>
|
||||
{{else}}
|
||||
<h2>{{i18n "user.change_password.choose"}}</h2>
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
<br />
|
||||
{{/if}}
|
||||
|
||||
<div class="input">
|
||||
<PasswordField
|
||||
@value={{this.accountPassword}}
|
||||
@capsLockOn={{this.capsLockOn}}
|
||||
type={{if this.maskPassword "password" "text"}}
|
||||
autofocus="autofocus"
|
||||
autocomplete="new-password"
|
||||
id="new-account-password"
|
||||
<SecondFactorForm
|
||||
@secondFactorMethod={{this.selectedSecondFactorMethod}}
|
||||
@secondFactorToken={{this.secondFactorToken}}
|
||||
@backupEnabled={{this.backupEnabled}}
|
||||
@totpEnabled={{this.secondFactorRequired}}
|
||||
@isLogin={{false}}
|
||||
>
|
||||
<SecondFactorInput
|
||||
{{on
|
||||
"input"
|
||||
(with-event-value (fn (mut this.secondFactorToken)))
|
||||
}}
|
||||
@secondFactorMethod={{this.selectedSecondFactorMethod}}
|
||||
value={{this.secondFactorToken}}
|
||||
id="second-factor"
|
||||
/>
|
||||
</SecondFactorForm>
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.displaySecurityKeyForm}}
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
@label="submit"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
<h2>{{i18n "user.change_password.choose_new"}}</h2>
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
<br />
|
||||
{{/if}}
|
||||
|
||||
<div class="input">
|
||||
<PasswordField
|
||||
@value={{this.accountPassword}}
|
||||
{{on "focusout" this.togglePasswordValidation}}
|
||||
@capsLockOn={{this.capsLockOn}}
|
||||
type={{if this.maskPassword "password" "text"}}
|
||||
autofocus="autofocus"
|
||||
autocomplete="new-password"
|
||||
id="new-account-password"
|
||||
/>
|
||||
<div class="change-password__password-info">
|
||||
<div class="change-password_tip-validation">
|
||||
{{#if this.showPasswordValidation}}
|
||||
<InputTip @validation={{this.passwordValidation}} />
|
||||
{{/if}}
|
||||
<div
|
||||
class="caps-lock-warning {{unless this.capsLockOn 'hidden'}}"
|
||||
>
|
||||
{{d-icon "triangle-exclamation"}}
|
||||
{{i18n "login.caps_lock_warning"}}
|
||||
</div>
|
||||
</div>
|
||||
<TogglePasswordMask
|
||||
@maskPassword={{this.maskPassword}}
|
||||
@togglePasswordMask={{this.togglePasswordMask}}
|
||||
/>
|
||||
|
||||
<div class="caps-lock-warning {{unless this.capsLockOn 'hidden'}}">
|
||||
{{d-icon "triangle-exclamation"}}
|
||||
{{i18n "login.caps_lock_warning"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<InputTip @validation={{this.passwordValidation}} />
|
||||
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
@label="user.change_password.set_password"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
{{/if}}
|
||||
</form>
|
||||
<DButton
|
||||
@action={{action "submit"}}
|
||||
@label="user.change_password.set_password"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||
import { blur, click, fillIn, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import sinon from "sinon";
|
||||
import PreloadStore from "discourse/lib/preload-store";
|
||||
|
@ -71,6 +71,8 @@ acceptance("Password Reset", function (needs) {
|
|||
assert.dom(".password-reset .tip.good").exists("input looks good");
|
||||
|
||||
await fillIn(".password-reset input", "123");
|
||||
await blur(".password-reset input");
|
||||
|
||||
assert.dom(".password-reset .tip.bad").exists("input is not valid");
|
||||
assert.dom(".password-reset .tip.bad").includesHtml(
|
||||
i18n("user.password.too_short", {
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
body.login-page,
|
||||
body.signup-page,
|
||||
body.invite-page {
|
||||
body.invite-page,
|
||||
body.password-reset-page {
|
||||
& ~ .powered-by-discourse,
|
||||
.above-main-container-outlet {
|
||||
display: none;
|
||||
|
@ -25,7 +26,8 @@ body.signup-page {
|
|||
|
||||
.login-fullpage,
|
||||
.signup-fullpage,
|
||||
.invites-show {
|
||||
.invites-show,
|
||||
.password-reset-page {
|
||||
.signup-body,
|
||||
.login-body {
|
||||
display: flex;
|
||||
|
@ -241,8 +243,6 @@ body.signup-page {
|
|||
.caps-lock-warning {
|
||||
color: var(--danger);
|
||||
font-size: var(--font-down-1);
|
||||
font-weight: bold;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.create-account__password-info {
|
||||
|
|
|
@ -33,28 +33,22 @@ body.invite-page {
|
|||
// the second button can wrap in some locales, and this helps alignment
|
||||
}
|
||||
|
||||
.password-reset {
|
||||
.instructions {
|
||||
label {
|
||||
color: var(--primary-medium);
|
||||
}
|
||||
}
|
||||
#new-account-password {
|
||||
width: 15em;
|
||||
}
|
||||
.tip {
|
||||
margin: 0 0 0.5em;
|
||||
}
|
||||
.toggle-password-mask {
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.password-reset-page {
|
||||
.caps-lock-warning {
|
||||
display: inline;
|
||||
}
|
||||
.change-password-form {
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 400px;
|
||||
input {
|
||||
padding: 0.75em 0.77em;
|
||||
min-width: 250px;
|
||||
margin-bottom: 0.25em;
|
||||
width: 100%;
|
||||
}
|
||||
.input {
|
||||
position: relative;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.tip {
|
||||
display: block;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user