web: add loading animation to flowexecutor

This commit is contained in:
Jens Langhammer 2021-02-21 22:01:35 +01:00
parent acc790f590
commit fb9880bff4
2 changed files with 81 additions and 58 deletions

View File

@ -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;

View File

@ -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``;
} }
} }