web: add loading animation to flowexecutor
This commit is contained in:
parent
acc790f590
commit
fb9880bff4
|
@ -6,17 +6,6 @@
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<style>
|
<style>
|
||||||
.ak-loading,
|
|
||||||
.pf-c-login__main >iframe {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.ak-hidden {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
.pf-c-background-image::before {
|
.pf-c-background-image::before {
|
||||||
background-image: url("{{ background_url }}");
|
background-image: url("{{ background_url }}");
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { gettext } from "django";
|
import { gettext } from "django";
|
||||||
import { LitElement, html, customElement, property, TemplateResult } from "lit-element";
|
import { LitElement, html, customElement, property, TemplateResult, CSSResult, css } from "lit-element";
|
||||||
import { unsafeHTML } from "lit-html/directives/unsafe-html";
|
import { unsafeHTML } from "lit-html/directives/unsafe-html";
|
||||||
import { getCookie } from "../../utils";
|
import { getCookie } from "../../utils";
|
||||||
import "../../elements/stages/identification/IdentificationStage";
|
import "../../elements/stages/identification/IdentificationStage";
|
||||||
|
@ -22,6 +22,8 @@ import { PromptChallenge } from "../../elements/stages/prompt/PromptStage";
|
||||||
import { AuthenticatorTOTPChallenge } from "../../elements/stages/authenticator_totp/AuthenticatorTOTPStage";
|
import { AuthenticatorTOTPChallenge } from "../../elements/stages/authenticator_totp/AuthenticatorTOTPStage";
|
||||||
import { AuthenticatorStaticChallenge } from "../../elements/stages/authenticator_static/AuthenticatorStaticStage";
|
import { AuthenticatorStaticChallenge } from "../../elements/stages/authenticator_static/AuthenticatorStaticStage";
|
||||||
import { WebAuthnAuthenticatorRegisterChallenge } from "../../elements/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
|
import { WebAuthnAuthenticatorRegisterChallenge } from "../../elements/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
|
||||||
|
import { COMMON_STYLES } from "../../common/styles";
|
||||||
|
import { SpinnerSize } from "../../elements/Spinner";
|
||||||
|
|
||||||
@customElement("ak-flow-executor")
|
@customElement("ak-flow-executor")
|
||||||
export class FlowExecutor extends LitElement {
|
export class FlowExecutor extends LitElement {
|
||||||
|
@ -31,8 +33,27 @@ export class FlowExecutor extends LitElement {
|
||||||
@property({attribute: false})
|
@property({attribute: false})
|
||||||
challenge?: Challenge;
|
challenge?: Challenge;
|
||||||
|
|
||||||
createRenderRoot(): Element | ShadowRoot {
|
@property({type: Boolean})
|
||||||
return this;
|
loading: boolean = false;
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return COMMON_STYLES.concat(css`
|
||||||
|
.ak-loading {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #0303039e;
|
||||||
|
}
|
||||||
|
.ak-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -49,6 +70,7 @@ export class FlowExecutor extends LitElement {
|
||||||
"X-CSRFToken": csrftoken,
|
"X-CSRFToken": csrftoken,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
this.loading = true;
|
||||||
return fetch(request, {
|
return fetch(request, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
mode: "same-origin",
|
mode: "same-origin",
|
||||||
|
@ -62,15 +84,21 @@ export class FlowExecutor extends LitElement {
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this.errorMessage(e);
|
this.errorMessage(e);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated(): void {
|
firstUpdated(): void {
|
||||||
|
this.loading = true;
|
||||||
Flow.executor(this.flowSlug).then((challenge) => {
|
Flow.executor(this.flowSlug).then((challenge) => {
|
||||||
this.challenge = challenge;
|
this.challenge = challenge;
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
// Catch JSON or Update errors
|
// Catch JSON or Update errors
|
||||||
this.errorMessage(e);
|
this.errorMessage(e);
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,55 +123,61 @@ export class FlowExecutor extends LitElement {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
loading(): TemplateResult {
|
renderLoading(): TemplateResult {
|
||||||
return html` <div class="pf-c-login__main-body ak-loading">
|
return html`<div class="ak-loading">
|
||||||
<span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
|
<ak-spinner size=${SpinnerSize.XLarge}></ak-spinner>
|
||||||
<span class="pf-c-spinner__clipper"></span>
|
|
||||||
<span class="pf-c-spinner__lead-ball"></span>
|
|
||||||
<span class="pf-c-spinner__tail-ball"></span>
|
|
||||||
</span>
|
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderChallenge(): TemplateResult {
|
||||||
|
if (!this.challenge) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
switch (this.challenge.type) {
|
||||||
|
case ChallengeTypes.redirect:
|
||||||
|
console.debug(`authentik/flows: redirecting to ${(this.challenge as RedirectChallenge).to}`);
|
||||||
|
window.location.assign((this.challenge as RedirectChallenge).to);
|
||||||
|
break;
|
||||||
|
case ChallengeTypes.shell:
|
||||||
|
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
|
||||||
|
case ChallengeTypes.native:
|
||||||
|
switch (this.challenge.component) {
|
||||||
|
case "ak-stage-identification":
|
||||||
|
return html`<ak-stage-identification .host=${this} .challenge=${this.challenge as IdentificationChallenge}></ak-stage-identification>`;
|
||||||
|
case "ak-stage-password":
|
||||||
|
return html`<ak-stage-password .host=${this} .challenge=${this.challenge as PasswordChallenge}></ak-stage-password>`;
|
||||||
|
case "ak-stage-consent":
|
||||||
|
return html`<ak-stage-consent .host=${this} .challenge=${this.challenge as ConsentChallenge}></ak-stage-consent>`;
|
||||||
|
case "ak-stage-email":
|
||||||
|
return html`<ak-stage-email .host=${this} .challenge=${this.challenge as EmailChallenge}></ak-stage-email>`;
|
||||||
|
case "ak-stage-autosubmit":
|
||||||
|
return html`<ak-stage-autosubmit .host=${this} .challenge=${this.challenge as AutosubmitChallenge}></ak-stage-autosubmit>`;
|
||||||
|
case "ak-stage-prompt":
|
||||||
|
return html`<ak-stage-prompt .host=${this} .challenge=${this.challenge as PromptChallenge}></ak-stage-prompt>`;
|
||||||
|
case "ak-stage-authenticator-totp":
|
||||||
|
return html`<ak-stage-authenticator-totp .host=${this} .challenge=${this.challenge as AuthenticatorTOTPChallenge}></ak-stage-authenticator-totp>`;
|
||||||
|
case "ak-stage-authenticator-static":
|
||||||
|
return html`<ak-stage-authenticator-static .host=${this} .challenge=${this.challenge as AuthenticatorStaticChallenge}></ak-stage-authenticator-static>`;
|
||||||
|
case "ak-stage-authenticator-webauthn-register":
|
||||||
|
return html`<ak-stage-authenticator-webauthn-register .host=${this} .challenge=${this.challenge as WebAuthnAuthenticatorRegisterChallenge}></ak-stage-authenticator-webauthn-register>`;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.debug(`authentik/flows: unexpected data type ${this.challenge.type}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
if (!this.challenge) {
|
if (!this.challenge) {
|
||||||
return this.loading();
|
return this.renderLoading();
|
||||||
}
|
}
|
||||||
switch(this.challenge.type) {
|
return html`
|
||||||
case ChallengeTypes.redirect:
|
${this.loading ? this.renderLoading() : html``}
|
||||||
console.debug(`authentik/flows: redirecting to ${(this.challenge as RedirectChallenge).to}`);
|
${this.renderChallenge()}
|
||||||
window.location.assign((this.challenge as RedirectChallenge).to);
|
`;
|
||||||
break;
|
|
||||||
case ChallengeTypes.shell:
|
|
||||||
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
|
|
||||||
case ChallengeTypes.native:
|
|
||||||
switch (this.challenge.component) {
|
|
||||||
case "ak-stage-identification":
|
|
||||||
return html`<ak-stage-identification .host=${this} .challenge=${this.challenge as IdentificationChallenge}></ak-stage-identification>`;
|
|
||||||
case "ak-stage-password":
|
|
||||||
return html`<ak-stage-password .host=${this} .challenge=${this.challenge as PasswordChallenge}></ak-stage-password>`;
|
|
||||||
case "ak-stage-consent":
|
|
||||||
return html`<ak-stage-consent .host=${this} .challenge=${this.challenge as ConsentChallenge}></ak-stage-consent>`;
|
|
||||||
case "ak-stage-email":
|
|
||||||
return html`<ak-stage-email .host=${this} .challenge=${this.challenge as EmailChallenge}></ak-stage-email>`;
|
|
||||||
case "ak-stage-autosubmit":
|
|
||||||
return html`<ak-stage-autosubmit .host=${this} .challenge=${this.challenge as AutosubmitChallenge}></ak-stage-autosubmit>`;
|
|
||||||
case "ak-stage-prompt":
|
|
||||||
return html`<ak-stage-prompt .host=${this} .challenge=${this.challenge as PromptChallenge}></ak-stage-prompt>`;
|
|
||||||
case "ak-stage-authenticator-totp":
|
|
||||||
return html`<ak-stage-authenticator-totp .host=${this} .challenge=${this.challenge as AuthenticatorTOTPChallenge}></ak-stage-authenticator-totp>`;
|
|
||||||
case "ak-stage-authenticator-static":
|
|
||||||
return html`<ak-stage-authenticator-static .host=${this} .challenge=${this.challenge as AuthenticatorStaticChallenge}></ak-stage-authenticator-static>`;
|
|
||||||
case "ak-stage-authenticator-webauthn-register":
|
|
||||||
return html`<ak-stage-authenticator-webauthn-register .host=${this} .challenge=${this.challenge as WebAuthnAuthenticatorRegisterChallenge}></ak-stage-authenticator-webauthn-register>`;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.debug(`authentik/flows: unexpected data type ${this.challenge.type}`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return html``;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue