From 0d94373f10d4c3152b176dce2dad8660a9015952 Mon Sep 17 00:00:00 2001 From: Ken Sternberg Date: Thu, 8 Jun 2023 11:25:13 -0700 Subject: [PATCH] web: password quality indicators Resolves issue 5165 This commit updates the password match indicator so that the user, and not the component, makes decisions about the names of the initial and confirmation inputs. --- .../password-match-indicator.stories.ts | 9 +++- .../password-match-indicator.ts | 42 ++++++++++--------- web/src/flow/stages/prompt/FieldRenderers.ts | 22 ++++++---- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/web/src/elements/password-match-indicator/password-match-indicator.stories.ts b/web/src/elements/password-match-indicator/password-match-indicator.stories.ts index eb6e85ea8..7d6c8a000 100644 --- a/web/src/elements/password-match-indicator/password-match-indicator.stories.ts +++ b/web/src/elements/password-match-indicator/password-match-indicator.stories.ts @@ -9,6 +9,11 @@ export default { export const Primary = () => html`

Type some text:

-

Type some other text:

- +

+ Type some other text: + +

`; diff --git a/web/src/elements/password-match-indicator/password-match-indicator.ts b/web/src/elements/password-match-indicator/password-match-indicator.ts index 745926faa..269c2a310 100644 --- a/web/src/elements/password-match-indicator/password-match-indicator.ts +++ b/web/src/elements/password-match-indicator/password-match-indicator.ts @@ -31,10 +31,14 @@ export class PasswordMatchIndicator extends AKElement { * throw an exception. */ @property({ attribute: true }) - src = ""; + first = ""; - sourceInput?: HTMLInputElement; - otherInput?: HTMLInputElement; + @property({ attribute: true }) + second = ""; + + firstElement?: HTMLInputElement; + + secondElement?: HTMLInputElement; @state() match = false; @@ -46,38 +50,38 @@ export class PasswordMatchIndicator extends AKElement { connectedCallback() { super.connectedCallback(); - this.input.addEventListener("keyup", this.checkPasswordMatch); - this.other.addEventListener("keyup", this.checkPasswordMatch); + this.firstInput.addEventListener("keyup", this.checkPasswordMatch); + this.secondInput.addEventListener("keyup", this.checkPasswordMatch); } disconnectedCallback() { - this.other.removeEventListener("keyup", this.checkPasswordMatch); - this.input.removeEventListener("keyup", this.checkPasswordMatch); + this.secondInput.removeEventListener("keyup", this.checkPasswordMatch); + this.firstInput.removeEventListener("keyup", this.checkPasswordMatch); super.disconnectedCallback(); } checkPasswordMatch() { this.match = - this.input.value.length > 0 && - this.other.value.length > 0 && - this.input.value === this.other.value; + this.firstInput.value.length > 0 && + this.secondInput.value.length > 0 && + this.firstInput.value === this.secondInput.value; } - get input() { - if (this.sourceInput) { - return this.sourceInput; + get firstInput() { + if (this.firstElement) { + return this.firstElement; } - return (this.sourceInput = findInput(this.getRootNode() as Element, ELEMENT, this.src)); + return (this.firstElement = findInput(this.getRootNode() as Element, ELEMENT, this.first)); } - get other() { - if (this.otherInput) { - return this.otherInput; + get secondInput() { + if (this.secondElement) { + return this.secondElement; } - return (this.otherInput = findInput( + return (this.secondElement = findInput( this.getRootNode() as Element, ELEMENT, - this.src.replace(/_repeat/, ""), + this.second, )); } diff --git a/web/src/flow/stages/prompt/FieldRenderers.ts b/web/src/flow/stages/prompt/FieldRenderers.ts index 2442d8f27..535605195 100644 --- a/web/src/flow/stages/prompt/FieldRenderers.ts +++ b/web/src/flow/stages/prompt/FieldRenderers.ts @@ -1,11 +1,13 @@ -import { rootInterface } from "@goauthentik/elements/Base"; import { LOCALES } from "@goauthentik/common/ui/locale"; +import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/password-match-indicator"; import "@goauthentik/elements/password-strength-indicator"; -import { unsafeHTML } from "lit/directives/unsafe-html.js"; -import { TemplateResult, html } from "lit"; + import { msg } from "@lit/localize"; -import { StagePrompt, CapabilitiesEnum, PromptTypeEnum } from "@goauthentik/api"; +import { TemplateResult, html } from "lit"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; + +import { CapabilitiesEnum, PromptTypeEnum, StagePrompt } from "@goauthentik/api"; export function password(prompt: StagePrompt) { return html``; } +const REPEAT = /_repeat/; + export function repeatPassword(prompt: StagePrompt) { + const first = `input[name="${prompt.fieldKey}"]`; + const second = `input[name="${prompt.fieldKey.replace(REPEAT, "")}"]`; + return html`
`; } export function renderPassword(prompt: StagePrompt) { - return /_repeat$/.test(prompt.fieldKey) ? repeatPassword(prompt) : password(prompt); + return REPEAT.test(prompt.fieldKey) ? repeatPassword(prompt) : password(prompt); } export function renderText(prompt: StagePrompt) { @@ -209,7 +217,7 @@ export function renderAkLocale(prompt: StagePrompt) { ?selected=${locale.code === prompt.initialValue} > ${locale.code.toUpperCase()} - ${locale.label()} - ` + `, ); return html`