web: Fix issues surrounding wizard step behavior. (#12779)
This resolves a few stateful situations which may arise when opening and closing wizard pages.
This commit is contained in:
		@ -52,6 +52,21 @@ export class PolicyWizard extends AKElement {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    selectListener = ({ detail }: CustomEvent<TypeCreate>) => {
 | 
				
			||||||
 | 
					        if (!this.wizard) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const { component, modelName } = detail;
 | 
				
			||||||
 | 
					        const idx = this.wizard.steps.indexOf("initial") + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Exclude all current steps starting with type-,
 | 
				
			||||||
 | 
					        // this happens when the user selects a type and then goes back
 | 
				
			||||||
 | 
					        this.wizard.steps = this.wizard.steps.filter((step) => !step.startsWith("type-"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.wizard.steps.splice(idx, 0, `type-${component}-${modelName}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.wizard.isValid = true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render(): TemplateResult {
 | 
					    render(): TemplateResult {
 | 
				
			||||||
        return html`
 | 
					        return html`
 | 
				
			||||||
            <ak-wizard
 | 
					            <ak-wizard
 | 
				
			||||||
@ -62,23 +77,10 @@ export class PolicyWizard extends AKElement {
 | 
				
			|||||||
                <ak-wizard-page-type-create
 | 
					                <ak-wizard-page-type-create
 | 
				
			||||||
                    slot="initial"
 | 
					                    slot="initial"
 | 
				
			||||||
                    .types=${this.policyTypes}
 | 
					                    .types=${this.policyTypes}
 | 
				
			||||||
                    @select=${(ev: CustomEvent<TypeCreate>) => {
 | 
					                    @select=${this.selectListener}
 | 
				
			||||||
                        if (!this.wizard) return;
 | 
					 | 
				
			||||||
                        const idx = this.wizard.steps.indexOf("initial") + 1;
 | 
					 | 
				
			||||||
                        // Exclude all current steps starting with type-,
 | 
					 | 
				
			||||||
                        // this happens when the user selects a type and then goes back
 | 
					 | 
				
			||||||
                        this.wizard.steps = this.wizard.steps.filter(
 | 
					 | 
				
			||||||
                            (step) => !step.startsWith("type-"),
 | 
					 | 
				
			||||||
                        );
 | 
					 | 
				
			||||||
                        this.wizard.steps.splice(
 | 
					 | 
				
			||||||
                            idx,
 | 
					 | 
				
			||||||
                            0,
 | 
					 | 
				
			||||||
                            `type-${ev.detail.component}-${ev.detail.modelName}`,
 | 
					 | 
				
			||||||
                        );
 | 
					 | 
				
			||||||
                        this.wizard.isValid = true;
 | 
					 | 
				
			||||||
                    }}
 | 
					 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                </ak-wizard-page-type-create>
 | 
					                </ak-wizard-page-type-create>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ${this.policyTypes.map((type) => {
 | 
					                ${this.policyTypes.map((type) => {
 | 
				
			||||||
                    return html`
 | 
					                    return html`
 | 
				
			||||||
                        <ak-wizard-page-form
 | 
					                        <ak-wizard-page-form
 | 
				
			||||||
 | 
				
			|||||||
@ -41,6 +41,7 @@ export class ActionWizardPage extends WizardPage {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    activeCallback = async (): Promise<void> => {
 | 
					    activeCallback = async (): Promise<void> => {
 | 
				
			||||||
        this.states = [];
 | 
					        this.states = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.host.actions.map((act, idx) => {
 | 
					        this.host.actions.map((act, idx) => {
 | 
				
			||||||
            this.states.push({
 | 
					            this.states.push({
 | 
				
			||||||
                action: act,
 | 
					                action: act,
 | 
				
			||||||
@ -48,9 +49,12 @@ export class ActionWizardPage extends WizardPage {
 | 
				
			|||||||
                idx: idx,
 | 
					                idx: idx,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.host.canBack = false;
 | 
					        this.host.canBack = false;
 | 
				
			||||||
        this.host.canCancel = false;
 | 
					        this.host.canCancel = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await this.run();
 | 
					        await this.run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Ensure wizard is closable, even when run() failed
 | 
					        // Ensure wizard is closable, even when run() failed
 | 
				
			||||||
        this.host.isValid = true;
 | 
					        this.host.isValid = true;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@ -59,15 +63,20 @@ export class ActionWizardPage extends WizardPage {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async run(): Promise<void> {
 | 
					    async run(): Promise<void> {
 | 
				
			||||||
        this.currentStep = this.states[0];
 | 
					        this.currentStep = this.states[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await new Promise((r) => setTimeout(r, 500));
 | 
					        await new Promise((r) => setTimeout(r, 500));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for await (const bundle of this.states) {
 | 
					        for await (const bundle of this.states) {
 | 
				
			||||||
            this.currentStep = bundle;
 | 
					            this.currentStep = bundle;
 | 
				
			||||||
            this.currentStep.state = ActionState.running;
 | 
					            this.currentStep.state = ActionState.running;
 | 
				
			||||||
            this.requestUpdate();
 | 
					            this.requestUpdate();
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                await bundle.action.run();
 | 
					                await bundle.action.run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                await new Promise((r) => setTimeout(r, 500));
 | 
					                await new Promise((r) => setTimeout(r, 500));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                this.currentStep.state = ActionState.done;
 | 
					                this.currentStep.state = ActionState.done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                this.requestUpdate();
 | 
					                this.requestUpdate();
 | 
				
			||||||
            } catch (exc) {
 | 
					            } catch (exc) {
 | 
				
			||||||
                if (exc instanceof ResponseError) {
 | 
					                if (exc instanceof ResponseError) {
 | 
				
			||||||
@ -75,12 +84,16 @@ export class ActionWizardPage extends WizardPage {
 | 
				
			|||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    this.currentStep.action.subText = (exc as Error).toString();
 | 
					                    this.currentStep.action.subText = (exc as Error).toString();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                this.currentStep.state = ActionState.failed;
 | 
					                this.currentStep.state = ActionState.failed;
 | 
				
			||||||
                this.requestUpdate();
 | 
					                this.requestUpdate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.host.isValid = true;
 | 
					        this.host.isValid = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.dispatchEvent(
 | 
					        this.dispatchEvent(
 | 
				
			||||||
            new CustomEvent(EVENT_REFRESH, {
 | 
					            new CustomEvent(EVENT_REFRESH, {
 | 
				
			||||||
                bubbles: true,
 | 
					                bubbles: true,
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
 | 
				
			|||||||
import { msg, str } from "@lit/localize";
 | 
					import { msg, str } from "@lit/localize";
 | 
				
			||||||
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
 | 
					import { CSSResult, TemplateResult, css, html, nothing } from "lit";
 | 
				
			||||||
import { customElement, property } from "lit/decorators.js";
 | 
					import { customElement, property } from "lit/decorators.js";
 | 
				
			||||||
 | 
					import { Ref, createRef, ref } from "lit/directives/ref.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import PFCard from "@patternfly/patternfly/components/Card/card.css";
 | 
					import PFCard from "@patternfly/patternfly/components/Card/card.css";
 | 
				
			||||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
					import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
				
			||||||
@ -21,6 +22,8 @@ export enum TypeCreateWizardPageLayouts {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@customElement("ak-wizard-page-type-create")
 | 
					@customElement("ak-wizard-page-type-create")
 | 
				
			||||||
export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
 | 
					export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
 | 
				
			||||||
 | 
					    //#region Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property({ attribute: false })
 | 
					    @property({ attribute: false })
 | 
				
			||||||
    types: TypeCreate[] = [];
 | 
					    types: TypeCreate[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,6 +33,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
 | 
				
			|||||||
    @property({ type: String })
 | 
					    @property({ type: String })
 | 
				
			||||||
    layout: TypeCreateWizardPageLayouts = TypeCreateWizardPageLayouts.list;
 | 
					    layout: TypeCreateWizardPageLayouts = TypeCreateWizardPageLayouts.list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static get styles(): CSSResult[] {
 | 
					    static get styles(): CSSResult[] {
 | 
				
			||||||
        return [
 | 
					        return [
 | 
				
			||||||
            PFBase,
 | 
					            PFBase,
 | 
				
			||||||
@ -49,10 +54,25 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
 | 
				
			|||||||
        ];
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sidebarLabel = () => msg("Select type");
 | 
					    //#region Refs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    formRef: Ref<HTMLFormElement> = createRef();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public sidebarLabel = () => msg("Select type");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public reset = () => {
 | 
				
			||||||
 | 
					        super.reset();
 | 
				
			||||||
 | 
					        this.selectedType = undefined;
 | 
				
			||||||
 | 
					        this.formRef.value?.reset();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    activeCallback = (): void => {
 | 
				
			||||||
 | 
					        const form = this.formRef.value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.host.isValid = form?.checkValidity() ?? false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    activeCallback: () => Promise<void> = async () => {
 | 
					 | 
				
			||||||
        this.host.isValid = false;
 | 
					 | 
				
			||||||
        if (this.selectedType) {
 | 
					        if (this.selectedType) {
 | 
				
			||||||
            this.selectDispatch(this.selectedType);
 | 
					            this.selectDispatch(this.selectedType);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -92,9 +112,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
 | 
				
			|||||||
                    data-ouid-component-type="ak-type-create-grid-card"
 | 
					                    data-ouid-component-type="ak-type-create-grid-card"
 | 
				
			||||||
                    data-ouid-component-name=${componentName}
 | 
					                    data-ouid-component-name=${componentName}
 | 
				
			||||||
                    @click=${() => {
 | 
					                    @click=${() => {
 | 
				
			||||||
                        if (requiresEnterprise) {
 | 
					                        if (requiresEnterprise) return;
 | 
				
			||||||
                            return;
 | 
					
 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        this.selectDispatch(type);
 | 
					                        this.selectDispatch(type);
 | 
				
			||||||
                        this.selectedType = type;
 | 
					                        this.selectedType = type;
 | 
				
			||||||
                    }}
 | 
					                    }}
 | 
				
			||||||
@ -120,11 +139,13 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    renderList(): TemplateResult {
 | 
					    renderList(): TemplateResult {
 | 
				
			||||||
        return html`<form
 | 
					        return html`<form
 | 
				
			||||||
 | 
					            ${ref(this.formRef)}
 | 
				
			||||||
            class="pf-c-form pf-m-horizontal"
 | 
					            class="pf-c-form pf-m-horizontal"
 | 
				
			||||||
            data-ouid-component-type="ak-type-create-list"
 | 
					            data-ouid-component-type="ak-type-create-list"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            ${this.types.map((type) => {
 | 
					            ${this.types.map((type) => {
 | 
				
			||||||
                const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
 | 
					                const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return html`<div
 | 
					                return html`<div
 | 
				
			||||||
                    class="pf-c-radio"
 | 
					                    class="pf-c-radio"
 | 
				
			||||||
                    data-ouid-component-type="ak-type-create-list-card"
 | 
					                    data-ouid-component-type="ak-type-create-list-card"
 | 
				
			||||||
@ -160,6 +181,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
 | 
				
			|||||||
                return this.renderGrid();
 | 
					                return this.renderGrid();
 | 
				
			||||||
            case TypeCreateWizardPageLayouts.list:
 | 
					            case TypeCreateWizardPageLayouts.list:
 | 
				
			||||||
                return this.renderList();
 | 
					                return this.renderList();
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                throw new Error(`Unknown layout: ${this.layout}`) as never;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,8 +5,9 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
 | 
				
			|||||||
import { msg } from "@lit/localize";
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
 | 
					import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
 | 
				
			||||||
import { property } from "@lit/reactive-element/decorators/property.js";
 | 
					import { property } from "@lit/reactive-element/decorators/property.js";
 | 
				
			||||||
import { CSSResult, TemplateResult, css, html } from "lit";
 | 
					import { CSSResult, TemplateResult, css, html, nothing } from "lit";
 | 
				
			||||||
import { state } from "lit/decorators.js";
 | 
					import { state } from "lit/decorators.js";
 | 
				
			||||||
 | 
					import { classMap } from "lit/directives/class-map.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import PFWizard from "@patternfly/patternfly/components/Wizard/wizard.css";
 | 
					import PFWizard from "@patternfly/patternfly/components/Wizard/wizard.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -20,21 +21,6 @@ export const ApplyActionsSlot = "apply-actions";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@customElement("ak-wizard")
 | 
					@customElement("ak-wizard")
 | 
				
			||||||
export class Wizard extends ModalButton {
 | 
					export class Wizard extends ModalButton {
 | 
				
			||||||
    @property({ type: Boolean })
 | 
					 | 
				
			||||||
    canCancel = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property({ type: Boolean })
 | 
					 | 
				
			||||||
    canBack = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property()
 | 
					 | 
				
			||||||
    header?: string;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property()
 | 
					 | 
				
			||||||
    description?: string;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property({ type: Boolean })
 | 
					 | 
				
			||||||
    isValid = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static get styles(): CSSResult[] {
 | 
					    static get styles(): CSSResult[] {
 | 
				
			||||||
        return super.styles.concat(
 | 
					        return super.styles.concat(
 | 
				
			||||||
            PFWizard,
 | 
					            PFWizard,
 | 
				
			||||||
@ -46,65 +32,138 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @state()
 | 
					    //#region Properties
 | 
				
			||||||
    _steps: string[] = [];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get steps(): string[] {
 | 
					    /**
 | 
				
			||||||
        return this._steps;
 | 
					     * Whether the wizard can be cancelled.
 | 
				
			||||||
    }
 | 
					     */
 | 
				
			||||||
 | 
					    @property({ type: Boolean })
 | 
				
			||||||
 | 
					    canCancel = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    set steps(steps: string[]) {
 | 
					    /**
 | 
				
			||||||
        const addApplyActionsSlot = this.steps.includes(ApplyActionsSlot);
 | 
					     * Whether the wizard can go back to the previous step.
 | 
				
			||||||
        this._steps = steps;
 | 
					     */
 | 
				
			||||||
        if (addApplyActionsSlot) {
 | 
					    @property({ type: Boolean })
 | 
				
			||||||
            this.steps.push(ApplyActionsSlot);
 | 
					    canBack = true;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.steps.forEach((step) => {
 | 
					 | 
				
			||||||
            const exists = this.querySelector(`[slot=${step}]`) !== null;
 | 
					 | 
				
			||||||
            if (!exists) {
 | 
					 | 
				
			||||||
                const el = document.createElement(step);
 | 
					 | 
				
			||||||
                el.slot = step;
 | 
					 | 
				
			||||||
                el.dataset["wizardmanaged"] = "true";
 | 
					 | 
				
			||||||
                this.appendChild(el);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        this.requestUpdate();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _initialSteps: string[] = [];
 | 
					    /**
 | 
				
			||||||
 | 
					     * Header title of the wizard.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @property()
 | 
				
			||||||
 | 
					    header?: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Description of the wizard.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @property()
 | 
				
			||||||
 | 
					    description?: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Whether the wizard is valid and can proceed to the next step.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @property({ type: Boolean })
 | 
				
			||||||
 | 
					    isValid = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Actions to display at the end of the wizard.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    @property({ attribute: false })
 | 
					    @property({ attribute: false })
 | 
				
			||||||
    actions: WizardAction[] = [];
 | 
					    actions: WizardAction[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @state()
 | 
					 | 
				
			||||||
    _currentStep?: WizardPage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    set currentStep(value: WizardPage | undefined) {
 | 
					 | 
				
			||||||
        this._currentStep = value;
 | 
					 | 
				
			||||||
        if (this._currentStep) {
 | 
					 | 
				
			||||||
            this._currentStep.activeCallback();
 | 
					 | 
				
			||||||
            this._currentStep.requestUpdate();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    get currentStep(): WizardPage | undefined {
 | 
					 | 
				
			||||||
        return this._currentStep;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property({ attribute: false })
 | 
					    @property({ attribute: false })
 | 
				
			||||||
    finalHandler: () => Promise<void> = () => {
 | 
					    finalHandler = () => {
 | 
				
			||||||
        return Promise.resolve();
 | 
					        return Promise.resolve();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property({ attribute: false })
 | 
					    @property({ attribute: false })
 | 
				
			||||||
    state: { [key: string]: unknown } = {};
 | 
					    state: { [key: string]: unknown } = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#region State
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Memoized step tag names.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @state()
 | 
				
			||||||
 | 
					    _steps: string[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Step tag names present in the wizard.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get steps(): string[] {
 | 
				
			||||||
 | 
					        return this._steps;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set steps(nextSteps: string[]) {
 | 
				
			||||||
 | 
					        const addApplyActionsSlot = this._steps.includes(ApplyActionsSlot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._steps = nextSteps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (addApplyActionsSlot) {
 | 
				
			||||||
 | 
					            this.steps.push(ApplyActionsSlot);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const step of this._steps) {
 | 
				
			||||||
 | 
					            const existingStepElement = this.getStepElementByName(step);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (existingStepElement) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const stepElement = document.createElement(step);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            stepElement.slot = step;
 | 
				
			||||||
 | 
					            stepElement.dataset["wizardmanaged"] = "true";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.appendChild(stepElement);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.requestUpdate();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Initial steps to reset to.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    _initialSteps: string[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @state()
 | 
				
			||||||
 | 
					    _activeStep?: WizardPage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set activeStepElement(nextActiveStepElement: WizardPage | undefined) {
 | 
				
			||||||
 | 
					        this._activeStep = nextActiveStepElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this._activeStep) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._activeStep.activeCallback();
 | 
				
			||||||
 | 
					        this._activeStep.requestUpdate();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The active step element being displayed.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get activeStepElement(): WizardPage | undefined {
 | 
				
			||||||
 | 
					        return this._activeStep;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getStepElementByIndex(stepIndex: number): WizardPage | null {
 | 
				
			||||||
 | 
					        const stepName = this._steps[stepIndex];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.querySelector<WizardPage>(`[slot=${stepName}]`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getStepElementByName(stepName: string): WizardPage | null {
 | 
				
			||||||
 | 
					        return this.querySelector<WizardPage>(`[slot=${stepName}]`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#region Lifecycle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    firstUpdated(): void {
 | 
					    firstUpdated(): void {
 | 
				
			||||||
        this._initialSteps = this._steps;
 | 
					        this._initialSteps = this._steps;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Add action to the beginning of the list
 | 
					     * Add action to the beginning of the list.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    addActionBefore(displayName: string, run: () => Promise<boolean>): void {
 | 
					    addActionBefore(displayName: string, run: () => Promise<boolean>): void {
 | 
				
			||||||
        this.actions.unshift({
 | 
					        this.actions.unshift({
 | 
				
			||||||
@ -114,7 +173,9 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Add action at the end of the list
 | 
					     * Add action at the end of the list.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @todo: Is this used?
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    addActionAfter(displayName: string, run: () => Promise<boolean>): void {
 | 
					    addActionAfter(displayName: string, run: () => Promise<boolean>): void {
 | 
				
			||||||
        this.actions.push({
 | 
					        this.actions.push({
 | 
				
			||||||
@ -123,17 +184,60 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderModalInner(): TemplateResult {
 | 
					    /**
 | 
				
			||||||
        const firstPage = this.querySelector<WizardPage>(`[slot=${this.steps[0]}]`);
 | 
					     * Reset the wizard to it's initial state.
 | 
				
			||||||
        if (!this.currentStep && firstPage) {
 | 
					     */
 | 
				
			||||||
            this.currentStep = firstPage;
 | 
					    reset = () => {
 | 
				
			||||||
 | 
					        this.open = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.querySelectorAll("[data-wizardmanaged=true]").forEach((el) => {
 | 
				
			||||||
 | 
					            el.remove();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const step of this.steps) {
 | 
				
			||||||
 | 
					            const stepElement = this.getStepElementByName(step);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            stepElement?.reset?.();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const currentIndex = this.currentStep ? this.steps.indexOf(this.currentStep.slot) : 0;
 | 
					
 | 
				
			||||||
        let lastPage = currentIndex === this.steps.length - 1;
 | 
					        this.steps = this._initialSteps;
 | 
				
			||||||
 | 
					        this.actions = [];
 | 
				
			||||||
 | 
					        this.state = {};
 | 
				
			||||||
 | 
					        this.activeStepElement = undefined;
 | 
				
			||||||
 | 
					        this.canBack = true;
 | 
				
			||||||
 | 
					        this.canCancel = true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //#region Rendering
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    renderModalInner(): TemplateResult {
 | 
				
			||||||
 | 
					        const firstPage = this.getStepElementByIndex(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.activeStepElement && firstPage) {
 | 
				
			||||||
 | 
					            this.activeStepElement = firstPage;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const activeStepIndex = this.activeStepElement
 | 
				
			||||||
 | 
					            ? this.steps.indexOf(this.activeStepElement.slot)
 | 
				
			||||||
 | 
					            : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let lastPage = activeStepIndex === this.steps.length - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (lastPage && !this.steps.includes("ak-wizard-page-action") && this.actions.length > 0) {
 | 
					        if (lastPage && !this.steps.includes("ak-wizard-page-action") && this.actions.length > 0) {
 | 
				
			||||||
            this.steps = this.steps.concat("ak-wizard-page-action");
 | 
					            this.steps = this.steps.concat("ak-wizard-page-action");
 | 
				
			||||||
            lastPage = currentIndex === this.steps.length - 1;
 | 
					            lastPage = activeStepIndex === this.steps.length - 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const navigateToPreviousStep = () => {
 | 
				
			||||||
 | 
					            const prevPage = this.getStepElementByIndex(activeStepIndex - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (prevPage) {
 | 
				
			||||||
 | 
					                this.activeStepElement = prevPage;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return html`<div class="pf-c-wizard">
 | 
					        return html`<div class="pf-c-wizard">
 | 
				
			||||||
            <div class="pf-c-wizard__header">
 | 
					            <div class="pf-c-wizard__header">
 | 
				
			||||||
                ${this.canCancel
 | 
					                ${this.canCancel
 | 
				
			||||||
@ -141,13 +245,11 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
                          class="pf-c-button pf-m-plain pf-c-wizard__close"
 | 
					                          class="pf-c-button pf-m-plain pf-c-wizard__close"
 | 
				
			||||||
                          type="button"
 | 
					                          type="button"
 | 
				
			||||||
                          aria-label="${msg("Close")}"
 | 
					                          aria-label="${msg("Close")}"
 | 
				
			||||||
                          @click=${() => {
 | 
					                          @click=${this.reset}
 | 
				
			||||||
                              this.reset();
 | 
					 | 
				
			||||||
                          }}
 | 
					 | 
				
			||||||
                      >
 | 
					                      >
 | 
				
			||||||
                          <i class="fas fa-times" aria-hidden="true"></i>
 | 
					                          <i class="fas fa-times" aria-hidden="true"></i>
 | 
				
			||||||
                      </button>`
 | 
					                      </button>`
 | 
				
			||||||
                    : html``}
 | 
					                    : nothing}
 | 
				
			||||||
                <h1 class="pf-c-title pf-m-3xl pf-c-wizard__title">${this.header}</h1>
 | 
					                <h1 class="pf-c-title pf-m-3xl pf-c-wizard__title">${this.header}</h1>
 | 
				
			||||||
                <p class="pf-c-wizard__description">${this.description}</p>
 | 
					                <p class="pf-c-wizard__description">${this.description}</p>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
@ -156,28 +258,25 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
                    <nav class="pf-c-wizard__nav">
 | 
					                    <nav class="pf-c-wizard__nav">
 | 
				
			||||||
                        <ol class="pf-c-wizard__nav-list">
 | 
					                        <ol class="pf-c-wizard__nav-list">
 | 
				
			||||||
                            ${this.steps.map((step, idx) => {
 | 
					                            ${this.steps.map((step, idx) => {
 | 
				
			||||||
                                const currentIdx = this.currentStep
 | 
					                                const stepEl = this.getStepElementByName(step);
 | 
				
			||||||
                                    ? this.steps.indexOf(this.currentStep.slot)
 | 
					
 | 
				
			||||||
                                    : 0;
 | 
					                                if (!stepEl) return html`<p>Unexpected missing step: ${step}</p>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                const sidebarLabel = stepEl.sidebarLabel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                return html`
 | 
					                                return html`
 | 
				
			||||||
                                    <li class="pf-c-wizard__nav-item">
 | 
					                                    <li class="pf-c-wizard__nav-item">
 | 
				
			||||||
                                        <button
 | 
					                                        <button
 | 
				
			||||||
                                            class="pf-c-wizard__nav-link ${idx === currentIdx
 | 
					                                            class=${classMap({
 | 
				
			||||||
                                                ? "pf-m-current"
 | 
					                                                "pf-c-wizard__nav-link": true,
 | 
				
			||||||
                                                : ""}"
 | 
					                                                "pf-m-current": idx === activeStepIndex,
 | 
				
			||||||
                                            ?disabled=${currentIdx < idx}
 | 
					                                            })}
 | 
				
			||||||
 | 
					                                            ?disabled=${activeStepIndex < idx}
 | 
				
			||||||
                                            @click=${() => {
 | 
					                                            @click=${() => {
 | 
				
			||||||
                                                const stepEl = this.querySelector<WizardPage>(
 | 
					                                                this.activeStepElement = stepEl;
 | 
				
			||||||
                                                    `[slot=${step}]`,
 | 
					 | 
				
			||||||
                                                );
 | 
					 | 
				
			||||||
                                                if (stepEl) {
 | 
					 | 
				
			||||||
                                                    this.currentStep = stepEl;
 | 
					 | 
				
			||||||
                                                }
 | 
					 | 
				
			||||||
                                            }}
 | 
					                                            }}
 | 
				
			||||||
                                        >
 | 
					                                        >
 | 
				
			||||||
                                            ${this.querySelector<WizardPage>(
 | 
					                                            ${sidebarLabel}
 | 
				
			||||||
                                                `[slot=${step}]`,
 | 
					 | 
				
			||||||
                                            )?.sidebarLabel()}
 | 
					 | 
				
			||||||
                                        </button>
 | 
					                                        </button>
 | 
				
			||||||
                                    </li>
 | 
					                                    </li>
 | 
				
			||||||
                                `;
 | 
					                                `;
 | 
				
			||||||
@ -186,7 +285,7 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
                    </nav>
 | 
					                    </nav>
 | 
				
			||||||
                    <main class="pf-c-wizard__main">
 | 
					                    <main class="pf-c-wizard__main">
 | 
				
			||||||
                        <div class="pf-c-wizard__main-body">
 | 
					                        <div class="pf-c-wizard__main-body">
 | 
				
			||||||
                            <slot name=${this.currentStep?.slot || this.steps[0]}></slot>
 | 
					                            <slot name=${this.activeStepElement?.slot || this.steps[0]}></slot>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </main>
 | 
					                    </main>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
@ -196,44 +295,38 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
                        type="submit"
 | 
					                        type="submit"
 | 
				
			||||||
                        ?disabled=${!this.isValid}
 | 
					                        ?disabled=${!this.isValid}
 | 
				
			||||||
                        @click=${async () => {
 | 
					                        @click=${async () => {
 | 
				
			||||||
                            const cb = await this.currentStep?.nextCallback();
 | 
					                            const completedStep = await this.activeStepElement?.nextCallback();
 | 
				
			||||||
                            if (!cb) {
 | 
					                            if (!completedStep) return;
 | 
				
			||||||
                                return;
 | 
					
 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            if (lastPage) {
 | 
					                            if (lastPage) {
 | 
				
			||||||
                                await this.finalHandler();
 | 
					                                await this.finalHandler();
 | 
				
			||||||
                                this.reset();
 | 
					                                this.reset();
 | 
				
			||||||
                            } else {
 | 
					
 | 
				
			||||||
                                const nextPage = this.querySelector<WizardPage>(
 | 
					                                return;
 | 
				
			||||||
                                    `[slot=${this.steps[currentIndex + 1]}]`,
 | 
					 | 
				
			||||||
                                );
 | 
					 | 
				
			||||||
                                if (nextPage) {
 | 
					 | 
				
			||||||
                                    this.currentStep = nextPage;
 | 
					 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            const nextPage = this.getStepElementByIndex(activeStepIndex + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (nextPage) {
 | 
				
			||||||
 | 
					                                this.activeStepElement = nextPage;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }}
 | 
					                        }}
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                        ${lastPage ? msg("Finish") : msg("Next")}
 | 
					                        ${lastPage ? msg("Finish") : msg("Next")}
 | 
				
			||||||
                    </button>
 | 
					                    </button>
 | 
				
			||||||
                    ${(this.currentStep ? this.steps.indexOf(this.currentStep.slot) : 0) > 0 &&
 | 
					                    ${(this.activeStepElement
 | 
				
			||||||
                    this.canBack
 | 
					                        ? this.steps.indexOf(this.activeStepElement.slot)
 | 
				
			||||||
 | 
					                        : 0) > 0 && this.canBack
 | 
				
			||||||
                        ? html`
 | 
					                        ? html`
 | 
				
			||||||
                              <button
 | 
					                              <button
 | 
				
			||||||
                                  class="pf-c-button pf-m-secondary"
 | 
					                                  class="pf-c-button pf-m-secondary"
 | 
				
			||||||
                                  type="button"
 | 
					                                  type="button"
 | 
				
			||||||
                                  @click=${() => {
 | 
					                                  @click=${navigateToPreviousStep}
 | 
				
			||||||
                                      const prevPage = this.querySelector<WizardPage>(
 | 
					 | 
				
			||||||
                                          `[slot=${this.steps[currentIndex - 1]}]`,
 | 
					 | 
				
			||||||
                                      );
 | 
					 | 
				
			||||||
                                      if (prevPage) {
 | 
					 | 
				
			||||||
                                          this.currentStep = prevPage;
 | 
					 | 
				
			||||||
                                      }
 | 
					 | 
				
			||||||
                                  }}
 | 
					 | 
				
			||||||
                              >
 | 
					                              >
 | 
				
			||||||
                                  ${msg("Back")}
 | 
					                                  ${msg("Back")}
 | 
				
			||||||
                              </button>
 | 
					                              </button>
 | 
				
			||||||
                          `
 | 
					                          `
 | 
				
			||||||
                        : html``}
 | 
					                        : nothing}
 | 
				
			||||||
                    ${this.canCancel
 | 
					                    ${this.canCancel
 | 
				
			||||||
                        ? html`<div class="pf-c-wizard__footer-cancel">
 | 
					                        ? html`<div class="pf-c-wizard__footer-cancel">
 | 
				
			||||||
                              <button
 | 
					                              <button
 | 
				
			||||||
@ -246,24 +339,13 @@ export class Wizard extends ModalButton {
 | 
				
			|||||||
                                  ${msg("Cancel")}
 | 
					                                  ${msg("Cancel")}
 | 
				
			||||||
                              </button>
 | 
					                              </button>
 | 
				
			||||||
                          </div>`
 | 
					                          </div>`
 | 
				
			||||||
                        : html``}
 | 
					                        : nothing}
 | 
				
			||||||
                </footer>
 | 
					                </footer>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>`;
 | 
					        </div>`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    reset(): void {
 | 
					    //#endregion
 | 
				
			||||||
        this.open = false;
 | 
					 | 
				
			||||||
        this.querySelectorAll("[data-wizardmanaged=true]").forEach((el) => {
 | 
					 | 
				
			||||||
            el.remove();
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        this.steps = this._initialSteps;
 | 
					 | 
				
			||||||
        this.actions = [];
 | 
					 | 
				
			||||||
        this.state = {};
 | 
					 | 
				
			||||||
        this.currentStep = undefined;
 | 
					 | 
				
			||||||
        this.canBack = true;
 | 
					 | 
				
			||||||
        this.canCancel = true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare global {
 | 
					declare global {
 | 
				
			||||||
 | 
				
			|||||||
@ -39,24 +39,24 @@ export class WizardFormPage extends WizardPage {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    inputCallback(): void {
 | 
					    inputCallback(): void {
 | 
				
			||||||
        const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
 | 
					        const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
 | 
				
			||||||
        if (!form) {
 | 
					
 | 
				
			||||||
            return;
 | 
					        if (!form) return;
 | 
				
			||||||
        }
 | 
					
 | 
				
			||||||
        const state = form.checkValidity();
 | 
					        const state = form.checkValidity();
 | 
				
			||||||
        this.host.isValid = state;
 | 
					        this.host.isValid = state;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nextCallback = async (): Promise<boolean> => {
 | 
					    nextCallback = async (): Promise<boolean> => {
 | 
				
			||||||
        const form = this.shadowRoot?.querySelector<WizardForm>("ak-wizard-form");
 | 
					        const form = this.shadowRoot?.querySelector<WizardForm>("ak-wizard-form");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!form) {
 | 
					        if (!form) {
 | 
				
			||||||
            console.warn("authentik/wizard: could not find form element");
 | 
					            console.warn("authentik/wizard: could not find form element");
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const response = await form.submit();
 | 
					        const response = await form.submit();
 | 
				
			||||||
        if (response === undefined) {
 | 
					
 | 
				
			||||||
            return false;
 | 
					        return Boolean(response);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return response;
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nextDataCallback: (data: KeyUnknown) => Promise<boolean> = async (): Promise<boolean> => {
 | 
					    nextDataCallback: (data: KeyUnknown) => Promise<boolean> = async (): Promise<boolean> => {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,14 +6,32 @@ import { customElement, property } from "lit/decorators.js";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
					import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Callback for when the page is brought into view.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type WizardPageActiveCallback = () => void | Promise<void>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Callback for when the next button is pressed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @returns `true` if the wizard can proceed to the next page, `false` otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type WizardPageNextCallback = () => boolean | Promise<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@customElement("ak-wizard-page")
 | 
					@customElement("ak-wizard-page")
 | 
				
			||||||
export class WizardPage extends AKElement {
 | 
					export class WizardPage extends AKElement {
 | 
				
			||||||
    static get styles(): CSSResult[] {
 | 
					    static get styles(): CSSResult[] {
 | 
				
			||||||
        return [PFBase];
 | 
					        return [PFBase];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The label to display in the sidebar for this page.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Override this to provide a custom label.
 | 
				
			||||||
 | 
					     * @todo: Should this be a getter or static property?
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    @property()
 | 
					    @property()
 | 
				
			||||||
    sidebarLabel: () => string = () => {
 | 
					    sidebarLabel = (): string => {
 | 
				
			||||||
        return "UNNAMED";
 | 
					        return "UNNAMED";
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -22,9 +40,18 @@ export class WizardPage extends AKElement {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Called when this is the page brought into view
 | 
					     * Reset the page to its initial state.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @abstract
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    activeCallback: () => Promise<void> = async () => {
 | 
					    public reset(): void | Promise<void> {
 | 
				
			||||||
 | 
					        console.debug(`authentik/wizard ${this.localName}: reset)`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Called when this is the page brought into view.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    activeCallback: WizardPageActiveCallback = () => {
 | 
				
			||||||
        this.host.isValid = false;
 | 
					        this.host.isValid = false;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -32,9 +59,11 @@ export class WizardPage extends AKElement {
 | 
				
			|||||||
     * Called when the `next` button on the wizard is pressed. For forms, results in the submission
 | 
					     * Called when the `next` button on the wizard is pressed. For forms, results in the submission
 | 
				
			||||||
     * of the current form to the back-end before being allowed to proceed to the next page. This is
 | 
					     * of the current form to the back-end before being allowed to proceed to the next page. This is
 | 
				
			||||||
     * sub-optimal if we want to collect multiple bits of data before finishing the whole course.
 | 
					     * sub-optimal if we want to collect multiple bits of data before finishing the whole course.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @returns `true` if the wizard can proceed to the next page, `false` otherwise.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    nextCallback: () => Promise<boolean> = async () => {
 | 
					    nextCallback: WizardPageNextCallback = () => {
 | 
				
			||||||
        return true;
 | 
					        return Promise.resolve(true);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    requestUpdate(
 | 
					    requestUpdate(
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user