web/flows: clean up loading, syntax and transitions (#10792)
* remove redundant bindings to ${true}
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* better ui for loading during autosubmit
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* default to loading label when setting ?loading
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* remove more html``
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* refactor non_field_errors
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* remove more html``
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* no loading label for overlay
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* fix
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* fix py
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* Revert "web: bump the wdio group across 2 directories with 5 updates (#10945)"
This reverts commit ea14c57989
.
---------
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
@ -11,6 +11,7 @@ import { WebsocketClient } from "@goauthentik/common/ws";
|
||||
import { Interface } from "@goauthentik/elements/Interface";
|
||||
import "@goauthentik/elements/LoadingOverlay";
|
||||
import "@goauthentik/elements/ak-locale-context";
|
||||
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import { themeImage } from "@goauthentik/elements/utils/images";
|
||||
import "@goauthentik/flow/sources/apple/AppleLoginInit";
|
||||
import "@goauthentik/flow/sources/plex/PlexLoginInit";
|
||||
@ -281,8 +282,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
|
||||
async renderChallenge(): Promise<TemplateResult> {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
switch (this.challenge?.component) {
|
||||
case "ak-stage-access-denied":
|
||||
@ -428,28 +428,9 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
}
|
||||
}
|
||||
|
||||
renderChallengeWrapper(): TemplateResult {
|
||||
const logo = html`<div class="pf-c-login__main-header pf-c-brand ak-brand">
|
||||
<img
|
||||
src="${themeImage(
|
||||
first(this.brand?.brandingLogo, globalAK()?.brand.brandingLogo, ""),
|
||||
)}"
|
||||
alt="authentik Logo"
|
||||
/>
|
||||
</div>`;
|
||||
if (!this.challenge) {
|
||||
return html`${logo}<ak-empty-state ?loading=${true} header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
return html`
|
||||
${this.loading ? html`<ak-loading-overlay></ak-loading-overlay>` : nothing} ${logo}
|
||||
${until(this.renderChallenge())}
|
||||
`;
|
||||
}
|
||||
|
||||
async renderInspector(): Promise<TemplateResult> {
|
||||
async renderInspector() {
|
||||
if (!this.inspectorOpen) {
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
await import("@goauthentik/flow/FlowInspector");
|
||||
return html`<ak-flow-inspector
|
||||
@ -489,7 +470,24 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
<div class="pf-c-login ${this.getLayout()}">
|
||||
<div class="${this.getLayoutClass()}">
|
||||
<div class="pf-c-login__main">
|
||||
${this.renderChallengeWrapper()}
|
||||
${this.loading && this.challenge
|
||||
? html`<ak-loading-overlay></ak-loading-overlay>`
|
||||
: nothing}
|
||||
<div
|
||||
class="pf-c-login__main-header pf-c-brand ak-brand"
|
||||
>
|
||||
<img
|
||||
src="${themeImage(
|
||||
first(
|
||||
this.brand?.brandingLogo,
|
||||
globalAK()?.brand.brandingLogo,
|
||||
DefaultBrand.brandingLogo,
|
||||
),
|
||||
)}"
|
||||
alt="authentik Logo"
|
||||
/>
|
||||
</div>
|
||||
${until(this.renderChallenge())}
|
||||
</div>
|
||||
<footer class="pf-c-login__footer">
|
||||
<ul class="pf-c-list pf-m-inline">
|
||||
|
@ -4,7 +4,7 @@ import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/Expand";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
@ -116,8 +116,7 @@ export class FlowInspector extends AKElement {
|
||||
}
|
||||
if (!this.state) {
|
||||
this.advanceHandler();
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<div class="pf-c-drawer__body pf-m-no-padding">
|
||||
<div class="pf-c-notification-drawer">
|
||||
@ -269,7 +268,7 @@ ${JSON.stringify(this.getStage(this.state.currentPlan?.nextPlannedStage?.stageOb
|
||||
</div>
|
||||
</div>
|
||||
</li>`
|
||||
: html``}
|
||||
: nothing}
|
||||
${this.state.currentPlan?.nextPlannedStage &&
|
||||
!this.state.isCompleted
|
||||
? html`<li
|
||||
@ -297,7 +296,7 @@ ${JSON.stringify(this.getStage(this.state.currentPlan?.nextPlannedStage?.stageOb
|
||||
</div>
|
||||
</div>
|
||||
</li>`
|
||||
: html``}
|
||||
: nothing}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,8 +30,7 @@ export class OAuth2DeviceCode extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
@ -46,7 +45,7 @@ export class OAuth2DeviceCode extends BaseStage<
|
||||
<p>${msg("Enter the code shown on your device.")}</p>
|
||||
<ak-form-element
|
||||
label="${msg("Code")}"
|
||||
?required="${true}"
|
||||
required
|
||||
class="pf-c-form__group"
|
||||
.errors=${(this.challenge?.responseErrors || {})["code"]}
|
||||
>
|
||||
|
@ -15,8 +15,7 @@ export class DeviceCodeFinish extends BaseStage<
|
||||
> {
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<ak-empty-state
|
||||
icon="fas fa-check"
|
||||
|
@ -40,11 +40,11 @@ export class AppleLoginInit extends BaseStage<AppleLoginChallenge, AppleChalleng
|
||||
this.isModalShown = true;
|
||||
};
|
||||
document.head.append(appleAuth);
|
||||
//Listen for authorization success
|
||||
// Listen for authorization success
|
||||
document.addEventListener("AppleIDSignInOnSuccess", () => {
|
||||
//handle successful response
|
||||
});
|
||||
//Listen for authorization failures
|
||||
// Listen for authorization failures
|
||||
document.addEventListener("AppleIDSignInOnFailure", (error) => {
|
||||
console.warn(error);
|
||||
this.isModalShown = false;
|
||||
@ -57,7 +57,7 @@ export class AppleLoginInit extends BaseStage<AppleLoginChallenge, AppleChalleng
|
||||
</header>
|
||||
<div class="pf-c-login__main-body">
|
||||
<form class="pf-c-form">
|
||||
<ak-empty-state ?loading="${true}"> </ak-empty-state>
|
||||
<ak-empty-state loading></ak-empty-state>
|
||||
${!this.isModalShown
|
||||
? html`<button
|
||||
class="pf-c-button pf-m-primary pf-m-block"
|
||||
|
@ -72,10 +72,7 @@ export class PlexLoginInit extends BaseStage<
|
||||
</header>
|
||||
<div class="pf-c-login__main-body">
|
||||
<form class="pf-c-form">
|
||||
<ak-empty-state
|
||||
?loading="${true}"
|
||||
header=${msg("Waiting for authentication...")}
|
||||
>
|
||||
<ak-empty-state loading header=${msg("Waiting for authentication...")}>
|
||||
</ak-empty-state>
|
||||
<hr class="pf-c-divider" />
|
||||
<p>${msg("If no Plex popup opens, click the button below.")}</p>
|
||||
|
@ -3,7 +3,7 @@ import "@goauthentik/flow/FormStatic";
|
||||
import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||
@ -38,8 +38,7 @@ export class FlowErrorStage extends BaseStage<FlowErrorChallenge, FlowChallengeR
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
@ -57,13 +56,13 @@ export class FlowErrorStage extends BaseStage<FlowErrorChallenge, FlowChallengeR
|
||||
? html`<div class="pf-c-form__group">
|
||||
<pre class="ak-exception">${this.challenge.traceback}</pre>
|
||||
</div>`
|
||||
: html``}
|
||||
: nothing}
|
||||
${this.challenge?.requestId
|
||||
? html`<div class="pf-c-form__group">
|
||||
<p>${msg("Request ID")}</p>
|
||||
<code>${this.challenge.requestId}</code>
|
||||
</div>`
|
||||
: html``}
|
||||
: nothing}
|
||||
</div>
|
||||
</ak-empty-state>
|
||||
</form>
|
||||
|
@ -66,7 +66,7 @@ export class RedirectStage extends BaseStage<RedirectChallenge, FlowChallengeRes
|
||||
>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}> </ak-empty-state>`;
|
||||
return html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
|
@ -26,8 +26,7 @@ export class AccessDeniedStage extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -65,8 +65,7 @@ export class AuthenticatorDuoStage extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -54,7 +54,7 @@ export class AuthenticatorSMSStage extends BaseStage<
|
||||
</ak-form-static>
|
||||
<ak-form-element
|
||||
label="${msg("Phone number")}"
|
||||
?required="${true}"
|
||||
required
|
||||
class="pf-c-form__group"
|
||||
.errors=${(this.challenge?.responseErrors || {})["phone_number"]}
|
||||
>
|
||||
@ -68,11 +68,7 @@ export class AuthenticatorSMSStage extends BaseStage<
|
||||
required
|
||||
/>
|
||||
</ak-form-element>
|
||||
${"non_field_errors" in (this.challenge?.responseErrors || {})
|
||||
? this.renderNonFieldErrors(
|
||||
this.challenge?.responseErrors?.non_field_errors || [],
|
||||
)
|
||||
: html``}
|
||||
${this.renderNonFieldErrors()}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||
${msg("Continue")}
|
||||
@ -109,11 +105,10 @@ export class AuthenticatorSMSStage extends BaseStage<
|
||||
</ak-form-static>
|
||||
<ak-form-element
|
||||
label="${msg("Code")}"
|
||||
?required="${true}"
|
||||
required
|
||||
class="pf-c-form__group"
|
||||
.errors=${(this.challenge?.responseErrors || {})["code"]}
|
||||
>
|
||||
<!-- @ts-ignore -->
|
||||
<input
|
||||
type="text"
|
||||
name="code"
|
||||
@ -126,11 +121,7 @@ export class AuthenticatorSMSStage extends BaseStage<
|
||||
required
|
||||
/>
|
||||
</ak-form-element>
|
||||
${"non_field_errors" in (this.challenge?.responseErrors || {})
|
||||
? this.renderNonFieldErrors(
|
||||
this.challenge?.responseErrors?.non_field_errors || [],
|
||||
)
|
||||
: html``}
|
||||
${this.renderNonFieldErrors()}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||
${msg("Continue")}
|
||||
@ -145,8 +136,7 @@ export class AuthenticatorSMSStage extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
if (this.challenge.phoneNumberRequired) {
|
||||
return this.renderPhoneNumber();
|
||||
|
@ -54,8 +54,7 @@ export class AuthenticatorStaticStage extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -48,8 +48,7 @@ export class AuthenticatorTOTPStage extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
@ -113,7 +112,7 @@ export class AuthenticatorTOTPStage extends BaseStage<
|
||||
</p>
|
||||
<ak-form-element
|
||||
label="${msg("Code")}"
|
||||
?required="${true}"
|
||||
required
|
||||
class="pf-c-form__group"
|
||||
.errors=${(this.challenge?.responseErrors || {})["code"]}
|
||||
>
|
||||
|
@ -6,7 +6,7 @@ import { BaseStage, StageHost, SubmitOptions } from "@goauthentik/flow/stages/ba
|
||||
import { PasswordManagerPrefill } from "@goauthentik/flow/stages/identification/IdentificationStage";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
@ -112,7 +112,7 @@ export class AuthenticatorValidateStage
|
||||
`);
|
||||
}
|
||||
|
||||
renderDevicePickerSingle(deviceChallenge: DeviceChallenge): TemplateResult {
|
||||
renderDevicePickerSingle(deviceChallenge: DeviceChallenge) {
|
||||
switch (deviceChallenge.deviceClass) {
|
||||
case DeviceClassesEnum.Duo:
|
||||
return html`<i class="fas fa-mobile-alt"></i>
|
||||
@ -147,7 +147,7 @@ export class AuthenticatorValidateStage
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
renderDevicePicker(): TemplateResult {
|
||||
@ -192,9 +192,9 @@ export class AuthenticatorValidateStage
|
||||
</ul>`;
|
||||
}
|
||||
|
||||
renderDeviceChallenge(): TemplateResult {
|
||||
renderDeviceChallenge() {
|
||||
if (!this.selectedDeviceChallenge) {
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
switch (this.selectedDeviceChallenge?.deviceClass) {
|
||||
case DeviceClassesEnum.Static:
|
||||
@ -224,13 +224,12 @@ export class AuthenticatorValidateStage
|
||||
>
|
||||
</ak-stage-authenticator-validate-duo>`;
|
||||
}
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
// User only has a single device class, so we don't show a picker
|
||||
if (this.challenge?.deviceChallenges.length === 1) {
|
||||
|
@ -33,8 +33,7 @@ export class AuthenticatorValidateStageWebCode extends BaseDeviceStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<div class="pf-c-login__main-body">
|
||||
<form
|
||||
@ -63,7 +62,7 @@ export class AuthenticatorValidateStageWebCode extends BaseDeviceStage<
|
||||
label="${this.deviceChallenge?.deviceClass === DeviceClassesEnum.Static
|
||||
? msg("Static token")
|
||||
: msg("Authentication code")}"
|
||||
?required="${true}"
|
||||
required
|
||||
class="pf-c-form__group"
|
||||
.errors=${(this.challenge?.responseErrors || {})["code"]}
|
||||
>
|
||||
|
@ -47,8 +47,7 @@ export class AuthenticatorValidateStageWebDuo extends BaseDeviceStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
const errors = this.challenge.responseErrors?.duo || [];
|
||||
const errorMessage = errors.map((err) => err.string);
|
||||
|
@ -2,7 +2,7 @@ import { AuthenticatorValidateStage } from "@goauthentik/flow/stages/authenticat
|
||||
import { BaseStage, FlowInfoChallenge, PendingUserChallenge } from "@goauthentik/flow/stages/base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { CSSResult, css, html, nothing } from "lit";
|
||||
import { property } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
@ -48,9 +48,9 @@ export class BaseDeviceStage<
|
||||
return this.host?.submit(payload) || Promise.resolve();
|
||||
}
|
||||
|
||||
renderReturnToDevicePicker(): TemplateResult {
|
||||
renderReturnToDevicePicker() {
|
||||
if (!this.showBackButton) {
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
return html`<button
|
||||
class="pf-c-button pf-m-secondary pf-m-block"
|
||||
|
@ -156,7 +156,7 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
|
||||
? html`<p class="pf-m-block">
|
||||
${this.challenge.responseErrors["response"][0].string}
|
||||
</p>`
|
||||
: html``}
|
||||
: nothing}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
${!this.registerRunning
|
||||
? html` <button
|
||||
|
@ -3,7 +3,7 @@ import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { customElement, query } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||
@ -19,43 +19,38 @@ export class AutosubmitStage extends BaseStage<
|
||||
AutosubmitChallenge,
|
||||
AutoSubmitChallengeResponseRequest
|
||||
> {
|
||||
@query("form")
|
||||
private form?: HTMLFormElement;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle];
|
||||
}
|
||||
|
||||
updated(): void {
|
||||
this.shadowRoot?.querySelectorAll("form").forEach((form) => {
|
||||
form.submit();
|
||||
});
|
||||
this.form?.submit();
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
let title = this.challenge.flowInfo?.title;
|
||||
if (this.challenge.title && this.challenge.title !== "") {
|
||||
title = this.challenge.title;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${title}</h1>
|
||||
</header>
|
||||
<div class="pf-c-login__main-body">
|
||||
<form class="pf-c-form" action="${this.challenge.url}" method="POST">
|
||||
${Object.entries(this.challenge.attrs).map(([key, value]) => {
|
||||
return html`<input
|
||||
type="hidden"
|
||||
name="${key as string}"
|
||||
value="${value as string}"
|
||||
/>`;
|
||||
})}
|
||||
<ak-empty-state ?loading="${true}"> </ak-empty-state>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-login__main-footer">
|
||||
<ul class="pf-c-login__main-footer-links"></ul>
|
||||
</footer>`;
|
||||
if (!title) {
|
||||
title = msg("Loading");
|
||||
}
|
||||
return html`<form class="pf-c-form" action="${this.challenge.url}" method="POST">
|
||||
${Object.entries(this.challenge.attrs).map(([key, value]) => {
|
||||
return html`<input
|
||||
type="hidden"
|
||||
name="${key as string}"
|
||||
value="${value as string}"
|
||||
/>`;
|
||||
})}
|
||||
<ak-empty-state loading title=${title}> </ak-empty-state>
|
||||
</form>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { html, nothing } from "lit";
|
||||
import { property } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
@ -43,8 +43,14 @@ export interface PendingUserChallenge {
|
||||
pendingUserAvatar?: string;
|
||||
}
|
||||
|
||||
export interface ResponseErrorsChallenge {
|
||||
responseErrors?: {
|
||||
[key: string]: Array<ErrorDetail>;
|
||||
};
|
||||
}
|
||||
|
||||
export class BaseStage<
|
||||
Tin extends FlowInfoChallenge & PendingUserChallenge,
|
||||
Tin extends FlowInfoChallenge & PendingUserChallenge & ResponseErrorsChallenge,
|
||||
Tout,
|
||||
> extends AKElement {
|
||||
host!: StageHost;
|
||||
@ -72,12 +78,17 @@ export class BaseStage<
|
||||
});
|
||||
}
|
||||
|
||||
renderNonFieldErrors(errors: ErrorDetail[]): TemplateResult {
|
||||
if (!errors) {
|
||||
return html``;
|
||||
renderNonFieldErrors() {
|
||||
const errors = this.challenge?.responseErrors || {};
|
||||
if (!("non_field_errors" in errors)) {
|
||||
return nothing;
|
||||
}
|
||||
const nonFieldErrors = errors["non_field_errors"];
|
||||
if (!nonFieldErrors) {
|
||||
return nothing;
|
||||
}
|
||||
return html`<div class="pf-c-form__alert">
|
||||
${errors.map((err) => {
|
||||
${nonFieldErrors.map((err) => {
|
||||
return html`<div class="pf-c-alert pf-m-inline pf-m-danger">
|
||||
<div class="pf-c-alert__icon">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
@ -88,9 +99,9 @@ export class BaseStage<
|
||||
</div>`;
|
||||
}
|
||||
|
||||
renderUserInfo(): TemplateResult {
|
||||
renderUserInfo() {
|
||||
if (!this.challenge.pendingUser || !this.challenge.pendingUserAvatar) {
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<ak-form-static
|
||||
|
@ -157,16 +157,12 @@ export class CaptchaStage extends BaseStage<CaptchaChallenge, CaptchaChallengeRe
|
||||
if (this.captchaInteractive) {
|
||||
return html`${this.captchaContainer}`;
|
||||
}
|
||||
return html`<ak-empty-state
|
||||
?loading=${true}
|
||||
header=${msg("Verifying...")}
|
||||
></ak-empty-state>`;
|
||||
return html`<ak-empty-state loading header=${msg("Verifying...")}></ak-empty-state>`;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -3,7 +3,7 @@ import "@goauthentik/flow/FormStatic";
|
||||
import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, html } from "lit";
|
||||
import { CSSResult, TemplateResult, html, nothing } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
@ -56,7 +56,7 @@ export class ConsentStage extends BaseStage<ConsentChallenge, ConsentChallengeRe
|
||||
${this.renderPermissions(this.challenge.permissions)}
|
||||
</ul>
|
||||
`
|
||||
: html``}
|
||||
: nothing}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -76,7 +76,7 @@ export class ConsentStage extends BaseStage<ConsentChallenge, ConsentChallengeRe
|
||||
${this.renderPermissions(this.challenge.permissions)}
|
||||
</ul>
|
||||
`
|
||||
: html``}
|
||||
: nothing}
|
||||
</div>
|
||||
<div class="pf-c-form__group pf-u-mt-md">
|
||||
${this.challenge.additionalPermissions.length > 0
|
||||
@ -88,15 +88,14 @@ export class ConsentStage extends BaseStage<ConsentChallenge, ConsentChallengeRe
|
||||
${this.renderPermissions(this.challenge.additionalPermissions)}
|
||||
</ul>
|
||||
`
|
||||
: html``}
|
||||
: nothing}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -23,8 +23,7 @@ export class DummyStage extends BaseStage<DummyChallenge, DummyChallengeResponse
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -22,8 +22,7 @@ export class EmailStage extends BaseStage<EmailChallenge, EmailChallengeResponse
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -198,9 +198,9 @@ export class IdentificationStage extends BaseStage<
|
||||
</li>`;
|
||||
}
|
||||
|
||||
renderFooter(): TemplateResult {
|
||||
renderFooter() {
|
||||
if (!this.challenge?.enrollUrl && !this.challenge?.recoveryUrl) {
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
return html`<div class="pf-c-login__main-footer-band">
|
||||
${this.challenge.enrollUrl
|
||||
@ -246,7 +246,7 @@ export class IdentificationStage extends BaseStage<
|
||||
: nothing}
|
||||
<ak-form-element
|
||||
label=${label}
|
||||
?required="${true}"
|
||||
required
|
||||
class="pf-c-form__group"
|
||||
.errors=${(this.challenge.responseErrors || {})["uid_field"]}
|
||||
>
|
||||
@ -273,9 +273,7 @@ export class IdentificationStage extends BaseStage<
|
||||
></ak-flow-input-password>
|
||||
`
|
||||
: nothing}
|
||||
${"non_field_errors" in (this.challenge?.responseErrors || {})
|
||||
? this.renderNonFieldErrors(this.challenge?.responseErrors?.non_field_errors || [])
|
||||
: nothing}
|
||||
${this.renderNonFieldErrors()}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||
${this.challenge.primaryAction}
|
||||
@ -288,8 +286,7 @@ export class IdentificationStage extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -33,8 +33,7 @@ export class PasswordStage extends BaseStage<PasswordChallenge, PasswordChalleng
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
@ -9,7 +9,7 @@ import "@goauthentik/elements/forms/FormElement";
|
||||
import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
||||
|
||||
@ -81,7 +81,7 @@ ${prompt.initialValue}</textarea
|
||||
name="${prompt.fieldKey}"
|
||||
placeholder="${prompt.placeholder}"
|
||||
class="pf-c-form-control"
|
||||
?readonly=${true}
|
||||
readonly
|
||||
value="${prompt.initialValue}"
|
||||
/>`;
|
||||
case PromptTypeEnum.TextAreaReadOnly:
|
||||
@ -222,9 +222,9 @@ ${prompt.initialValue}</textarea
|
||||
}
|
||||
}
|
||||
|
||||
renderPromptHelpText(prompt: StagePrompt): TemplateResult {
|
||||
renderPromptHelpText(prompt: StagePrompt) {
|
||||
if (prompt.subText === "") {
|
||||
return html``;
|
||||
return nothing;
|
||||
}
|
||||
return html`<p class="pf-c-form__helper-text">${unsafeHTML(prompt.subText)}</p>`;
|
||||
}
|
||||
@ -253,7 +253,7 @@ ${prompt.initialValue}</textarea
|
||||
<label class="pf-c-check__label" for="${prompt.fieldKey}">${prompt.label}</label>
|
||||
${prompt.required
|
||||
? html`<p class="pf-c-form__helper-text">${msg("Required.")}</p>`
|
||||
: html``}
|
||||
: nothing}
|
||||
<p class="pf-c-form__helper-text">${unsafeHTML(prompt.subText)}</p>
|
||||
</div>`;
|
||||
}
|
||||
@ -280,8 +280,7 @@ ${prompt.initialValue}</textarea
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
@ -296,12 +295,7 @@ ${prompt.initialValue}</textarea
|
||||
${this.challenge.fields.map((prompt) => {
|
||||
return this.renderField(prompt);
|
||||
})}
|
||||
${"non_field_errors" in (this.challenge?.responseErrors || {})
|
||||
? this.renderNonFieldErrors(
|
||||
this.challenge?.responseErrors?.non_field_errors || [],
|
||||
)
|
||||
: html``}
|
||||
${this.renderContinue()}
|
||||
${this.renderNonFieldErrors()} ${this.renderContinue()}
|
||||
</form>
|
||||
</div>
|
||||
<footer class="pf-c-login__main-footer">
|
||||
|
@ -29,8 +29,7 @@ export class PasswordStage extends BaseStage<
|
||||
|
||||
render(): TemplateResult {
|
||||
if (!this.challenge) {
|
||||
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-empty-state loading> </ak-empty-state>`;
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||
|
Reference in New Issue
Block a user