web: reset

As I said, I greatly dislike having to be dependent upon "resets"; I prefer my
data to be de novo going into a "new" transaction.  That said, we work with
what we've got; I've created an event generated by the wizard that says the
modal just closed; anything wrapping and implementing the wizard can then
capture that event and reset the data.  I've also added a pair of functions
that create the two states (what step, what form data) anew, so that resetting
is as trivial as initializing (and is exactly the same, code-wise).
This commit is contained in:
Ken Sternberg 2023-09-02 10:16:17 -07:00
parent c889801bb3
commit b7ea6d163b
11 changed files with 25 additions and 25 deletions

View file

@ -55,6 +55,7 @@ export class ApplicationWizard extends CustomListenerElement(AKElement) {
constructor() { constructor() {
super(); super();
this.handleUpdate = this.handleUpdate.bind(this); this.handleUpdate = this.handleUpdate.bind(this);
this.handleClosed = this.handleClosed.bind(this);
} }
get step() { get step() {
@ -65,10 +66,12 @@ export class ApplicationWizard extends CustomListenerElement(AKElement) {
super.connectedCallback(); super.connectedCallback();
new ContextRoot().attach(this.parentElement!); new ContextRoot().attach(this.parentElement!);
this.addCustomListener("ak-application-wizard-update", this.handleUpdate); this.addCustomListener("ak-application-wizard-update", this.handleUpdate);
this.addCustomListener("ak-wizard-closed", this.handleClosed);
} }
disconnectedCallback() { disconnectedCallback() {
this.removeCustomListener("ak-application-wizard-update", this.handleUpdate); this.removeCustomListener("ak-application-wizard-update", this.handleUpdate);
this.removeCustomListener("ak-wizard-closed", this.handleClosed);
super.disconnectedCallback(); super.disconnectedCallback();
} }
@ -124,6 +127,12 @@ export class ApplicationWizard extends CustomListenerElement(AKElement) {
this.wizardStateProvider.setValue(this.wizardState); this.wizardStateProvider.setValue(this.wizardState);
} }
handleClosed() {
this.steps = newSteps();
this.wizardState = freshWizardState();
this.wizardStateProvider.setValue(this.wizardState);
}
render() { render() {
return html` return html`
<ak-wizard-main <ak-wizard-main

View file

@ -38,7 +38,7 @@ export class ApplicationWizardApplicationDetails extends BasePanel {
validator() { validator() {
return this.form.reportValidity(); return this.form.reportValidity();
} }
render(): TemplateResult { render(): TemplateResult {
return html` <form class="pf-c-form pf-m-horizontal" @input=${this.handleChange}> return html` <form class="pf-c-form pf-m-horizontal" @input=${this.handleChange}>
<ak-text-input <ak-text-input

View file

@ -26,7 +26,6 @@ import type { ModelRequest } from "@goauthentik/api";
import BasePanel from "../BasePanel"; import BasePanel from "../BasePanel";
import providerModelsList from "../auth-method-choice/ak-application-wizard-authentication-method-choice.choices"; import providerModelsList from "../auth-method-choice/ak-application-wizard-authentication-method-choice.choices";
import { type WizardStateUpdate } from "../types";
function cleanApplication(app: Partial<ApplicationRequest>): ApplicationRequest { function cleanApplication(app: Partial<ApplicationRequest>): ApplicationRequest {
return { return {
@ -116,7 +115,7 @@ export class ApplicationWizardCommitApplication extends BasePanel {
} }
this.response = network_resolution.value; this.response = network_resolution.value;
this.dispatchCustomEvent(EVENT_REFRESH); this.dispatchCustomEvent(EVENT_REFRESH);
this.dispatchWizardUpdate({ status: "submitted"}); this.dispatchWizardUpdate({ status: "submitted" });
this.commitState = doneState; this.commitState = doneState;
} }
}); });

View file

@ -14,15 +14,10 @@ export class ApplicationWizardProviderPageBase extends BasePanel {
[target.name]: value, [target.name]: value,
}, },
}, },
status: this.form.checkValidity() ? "valid" : "invalid" status: this.form.checkValidity() ? "valid" : "invalid",
}); });
} }
shouldUpdate(changed: Map<string, any>) {
console.log("CHANGED:", JSON.stringify(Array.from(changed.entries()), null, 2));
return true;
}
validator() { validator() {
return this.form.reportValidity(); return this.form.reportValidity();
} }

View file

@ -25,6 +25,6 @@ export interface WizardState {
type StatusType = "invalid" | "valid" | "submitted" | "failed"; type StatusType = "invalid" | "valid" | "submitted" | "failed";
export type WizardStateUpdate = { export type WizardStateUpdate = {
update?: Partial<WizardState>, update?: Partial<WizardState>;
status?: StatusType, status?: StatusType;
}; };

View file

@ -71,13 +71,11 @@ export class AkWizardFrame extends CustomEmitterElement(ModalButton) {
} }
renderModalInner() { renderModalInner() {
// prettier-ignore
return html`<div class="pf-c-wizard"> return html`<div class="pf-c-wizard">
${this.renderHeader()} ${this.renderHeader()}
<div class="pf-c-wizard__outer-wrap"> <div class="pf-c-wizard__outer-wrap">
<div class="pf-c-wizard__inner-wrap"> <div class="pf-c-wizard__inner-wrap">
${this.renderNavigation()} ${this.renderNavigation()} ${this.renderMainSection()}
${this.renderMainSection()}
</div> </div>
${this.renderFooter()} ${this.renderFooter()}
</div> </div>

View file

@ -1,5 +1,5 @@
import { AKElement } from "@goauthentik/elements/Base"; import { AKElement } from "@goauthentik/elements/Base";
import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter"; import { CustomEmitterElement, CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter";
import { html } from "lit"; import { html } from "lit";
import { customElement, property, query, state } from "lit/decorators.js"; import { customElement, property, query, state } from "lit/decorators.js";
@ -45,7 +45,7 @@ const hasValidator = (v: any): v is Required<Pick<WizardPanel, "validator">> =>
*/ */
@customElement("ak-wizard-main") @customElement("ak-wizard-main")
export class AkWizardMain extends CustomListenerElement(AKElement) { export class AkWizardMain extends CustomEmitterElement(CustomListenerElement(AKElement)) {
static get styles() { static get styles() {
return [PFBase, PFButton, PFRadio]; return [PFBase, PFButton, PFRadio];
} }
@ -167,6 +167,7 @@ export class AkWizardMain extends CustomListenerElement(AKElement) {
case "close": { case "close": {
this.currentStep = 0; this.currentStep = 0;
this.frame.open = false; this.frame.open = false;
this.dispatchCustomEvent('ak-wizard-closed');
} }
} }
} }

View file

@ -1,4 +1,5 @@
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { WizardButton } from "./types"; import { WizardButton } from "./types";
export const NextStep: WizardButton = [msg("Next"), "next"]; export const NextStep: WizardButton = [msg("Next"), "next"];
@ -10,4 +11,3 @@ export const SubmitStep: WizardButton = [msg("Submit"), "next"];
export const CancelWizard: WizardButton = [msg("Cancel"), "close"]; export const CancelWizard: WizardButton = [msg("Cancel"), "close"];
export const CloseWizard: WizardButton = [msg("Close"), "close"]; export const CloseWizard: WizardButton = [msg("Close"), "close"];

View file

@ -36,8 +36,8 @@ export class AkDemoWizard extends AKElement {
<ak-wizard-context .steps=${this.steps}> <ak-wizard-context .steps=${this.steps}>
<ak-wizard-frame <ak-wizard-frame
?open=${this.open} ?open=${this.open}
header=${this.header} header=${this.header}
canCancel canCancel
description=${ifDefined(this.description)} description=${ifDefined(this.description)}
> >
<button slot="trigger" class="pf-c-button pf-m-primary">Show Wizard</button> <button slot="trigger" class="pf-c-button pf-m-primary">Show Wizard</button>

View file

@ -2,15 +2,13 @@ import { TemplateResult } from "lit";
export type WizardNavCommand = "next" | "back" | "close" | ["goto", number]; export type WizardNavCommand = "next" | "back" | "close" | ["goto", number];
// The label of the button, the command the button should execute, and if the button // The label of the button, the command the button should execute, and if the button
// should be marked "disabled." // should be marked "disabled."
export type WizardButton = [string, WizardNavCommand, boolean?]; export type WizardButton = [string, WizardNavCommand, boolean?];
export interface WizardStep { export interface WizardStep {
// The name of the step, as shown in the navigation. // The name of the step, as shown in the navigation.
label: string; label: string;
// A function which returns the html for rendering the actual content of the step, its form and // A function which returns the html for rendering the actual content of the step, its form and
// such. // such.

View file

@ -1,7 +1,7 @@
import { AKElement } from "@goauthentik/elements/Base"; import { AKElement } from "@goauthentik/elements/Base";
import { PFSize } from "@goauthentik/elements/Spinner"; import { PFSize } from "@goauthentik/elements/Spinner";
import { CSSResult, TemplateResult, css, html } 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 PFBackdrop from "@patternfly/patternfly/components/Backdrop/backdrop.css"; import PFBackdrop from "@patternfly/patternfly/components/Backdrop/backdrop.css";
@ -100,7 +100,7 @@ export class ModalButton extends AKElement {
}); });
} }
renderModalInner(): TemplateResult { renderModalInner(): TemplateResult | typeof nothing {
return html`<slot name="modal"></slot>`; return html`<slot name="modal"></slot>`;
} }
@ -136,6 +136,6 @@ export class ModalButton extends AKElement {
render(): TemplateResult { render(): TemplateResult {
return html` <slot name="trigger" @click=${() => this.onClick()}></slot> return html` <slot name="trigger" @click=${() => this.onClick()}></slot>
${this.open ? this.renderModal() : ""}`; ${this.open ? this.renderModal() : nothing}`;
} }
} }