Repository: goauthentik/authentik
File: web/src/flow/stages/identification/IdentificationStage.ts (TypeScript)

Code before:
            type="button"
            @click=${() => this.dispatchChallengeToHost(source.challenge)}
            part="source-item"
            name=${`source-${kebabCase(source.name)}`}
            class="pf-c-button source-button"
            aria-label=${msg(str`Continue with ${source.name}`)}
        >
            <span class="pf-c-button__icon pf-m-start">${icon}</span>
            ${showLabels ? source.name : ""}
        </button>`;
    }

    renderPromotedSource(source: LoginSource) {
        return html`<button
            type="button"
            @click=${() => this.dispatchChallengeToHost(source.challenge)}
            part="source-item source-item-promoted"
            name=${`source-${kebabCase(source.name)}`}
            class="pf-c-button pf-m-primary pf-m-block source-button source-button-promoted"
            aria-label=${msg(str`Continue with ${source.name}`)}
        >
            ${msg(str`Continue with ${source.name}`)}
        </button>`;
    }

    renderSource(source: LoginSource, showLabels: boolean) {
        return source.promoted
            ? this.renderPromotedSource(source)
            : this.renderDefaultSource(source, showLabels);
    }

    renderRecoveryPhase() {
        const message = msg(
            "Enter the email associated with your account, and we'll send you a link to reset your password.",
        );
        return html` <p>${message}</p> `;
    }

    renderIdentityInput(challenge: IdentificationChallenge) {
        const fields = (challenge.userFields || []).sort();
        const type =
            fields.includes(UserFieldsEnum.Email) && fields.length === 1 ? "email" : "text";
        const label = OR_LIST_FORMATTERS.format(fields.map((f) => UI_FIELDS[f]));
        const passkeyChallenge = (challenge as PasskeyChallenge)?.passkeyChallenge;
        const autocomplete: AutoFill = passkeyChallenge ? "username webauthn" : "username";

        return html`<div class="pf-c-form__group">
            ${AKLabel({ required: true, htmlFor: this.inputID }, label)}
            <input
                id=${this.inputID}
                type=${type}

Review comment (suggestion):
```suggestion
    protected renderSource(source: LoginSource, showLabels: boolean): SlottedTemplateResult {
```

Code after:
        if (!this.host) return;
        this.host.challenge = challenge;
    };

    protected renderRecoveryMessage() {
        return html`
            <p>${msg("Enter the email address or username associated with your account.")}</p>
        `;
    }

    protected renderUidField(
        id: string,
        type: string,
        label: string,
        username: EmptyString,
        autocomplete: string,
    ) {
        return html`<input
            id=${id}
            type=${type}
            name="uidField"
            placeholder=${label}
            autofocus
            autocomplete=${autocomplete}
            spellcheck="false"
            class="pf-c-form-control"
            value=${username ?? ""}
            required
        />`;
    }

    protected renderPasswordFields(challenge: IdentificationChallenge) {
        const { allowShowPassword } = challenge;
        return html`
            <ak-flow-input-password
                label=${msg("Password")}
                input-id="ak-stage-identification-password"
                class="pf-c-form__group"
                .errors=${challenge.responseErrors?.password}
                ?allow-show-password=${allowShowPassword}
                prefill=${PasswordManagerPrefill.password ?? ""}
            ></ak-flow-input-password>
        `;
    }

    protected renderCaptcha(captchaChallenge: CaptchaChallenge) {
        return html`
            <div class="captcha-container">
                <ak-stage-captcha
                    .challenge=${captchaChallenge}
                    .onTokenChange=${this.#tokenChangeListener}