web: reify the data loop
I was very unhappy with the "update this dot-path" mechanism I was using earlier; it was hard for me to read and understand what was happening, and I wrote the darned thing. I decided instead to go with a hard substitution model; each phase of the wizard is responsible for updating the *entire* payload, mostly by creating a new payload and substituting the field value associated with the event. On the receiver, we have to do that *again* to handle the swapping of providers when the user chooses one and then another. It looks clunky, and it is, but it's *legible*; a junior dev could understand what it's doing, and that's the goal.
This commit is contained in:
parent
5e1854f74e
commit
09fedcacf0
|
@ -2,7 +2,7 @@ import { WizardPanel } from "@goauthentik/components/ak-wizard-main/types";
|
||||||
import { AKElement } from "@goauthentik/elements/Base";
|
import { AKElement } from "@goauthentik/elements/Base";
|
||||||
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
|
||||||
|
|
||||||
import { consume } from "@lit/context";
|
import { consume } from "@lit-labs/context";
|
||||||
import { query } from "@lit/reactive-element/decorators.js";
|
import { query } from "@lit/reactive-element/decorators.js";
|
||||||
|
|
||||||
import { styles as AwadStyles } from "./BasePanel.css";
|
import { styles as AwadStyles } from "./BasePanel.css";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createContext } from "@lit/context";
|
import { createContext } from "@lit-labs/context";
|
||||||
|
|
||||||
import { ApplicationWizardState } from "./types";
|
import { ApplicationWizardState } from "./types";
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { merge } from "@goauthentik/common/merge";
|
|
||||||
import { AkWizard } from "@goauthentik/components/ak-wizard-main/AkWizard";
|
import { AkWizard } from "@goauthentik/components/ak-wizard-main/AkWizard";
|
||||||
import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter";
|
import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter";
|
||||||
|
|
||||||
import { ContextProvider } from "@lit/context";
|
import { ContextProvider } from "@lit-labs/context";
|
||||||
import { msg } from "@lit/localize";
|
import { msg } from "@lit/localize";
|
||||||
import { customElement, state } from "lit/decorators.js";
|
import { customElement, state } from "lit/decorators.js";
|
||||||
|
|
||||||
|
@ -97,7 +96,22 @@ export class ApplicationWizard extends CustomListenerElement(
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.wizardState = merge(this.wizardState, update) as ApplicationWizardState;
|
// Being extremely explicit about how a wizard state gets built, so that we preserve as much
|
||||||
|
// information as possible. This is much more predictable than using a generic merge.
|
||||||
|
|
||||||
|
this.wizardState = {
|
||||||
|
...this.wizardState,
|
||||||
|
app: {
|
||||||
|
...this.wizardState.app ?? {},
|
||||||
|
...update.app ?? {}
|
||||||
|
},
|
||||||
|
provider: {
|
||||||
|
...this.wizardState.provider ?? {},
|
||||||
|
...update.provider ?? {}
|
||||||
|
},
|
||||||
|
providerModel: update.providerModel
|
||||||
|
}
|
||||||
|
|
||||||
this.wizardStateProvider.setValue(this.wizardState);
|
this.wizardStateProvider.setValue(this.wizardState);
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,9 @@ export class ApplicationWizardApplicationDetails extends BasePanel {
|
||||||
const value = target.type === "checkbox" ? target.checked : target.value;
|
const value = target.type === "checkbox" ? target.checked : target.value;
|
||||||
this.dispatchWizardUpdate({
|
this.dispatchWizardUpdate({
|
||||||
update: {
|
update: {
|
||||||
|
...this.wizard,
|
||||||
app: {
|
app: {
|
||||||
|
...this.wizard.app,
|
||||||
[target.name]: value,
|
[target.name]: value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,7 +25,10 @@ export class ApplicationWizardAuthenticationMethodChoice extends BasePanel {
|
||||||
handleChoice(ev: InputEvent) {
|
handleChoice(ev: InputEvent) {
|
||||||
const target = ev.target as HTMLInputElement;
|
const target = ev.target as HTMLInputElement;
|
||||||
this.dispatchWizardUpdate({
|
this.dispatchWizardUpdate({
|
||||||
update: { providerModel: target.value },
|
update: {
|
||||||
|
...this.wizard,
|
||||||
|
providerModel: target.value
|
||||||
|
},
|
||||||
status: this.validator() ? "valid" : "invalid",
|
status: this.validator() ? "valid" : "invalid",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,6 @@ export class ApplicationWizardCommitApplication extends BasePanel {
|
||||||
if (body["provider"] !== undefined) {
|
if (body["provider"] !== undefined) {
|
||||||
errs = [...errs, msg("In the Provider:"), ...spaceify(body["provider"])];
|
errs = [...errs, msg("In the Provider:"), ...spaceify(body["provider"])];
|
||||||
}
|
}
|
||||||
console.log(body, errs);
|
|
||||||
return errs;
|
return errs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,9 @@ export class ApplicationWizardProviderPageBase extends BasePanel {
|
||||||
const value = target.type === "checkbox" ? target.checked : target.value;
|
const value = target.type === "checkbox" ? target.checked : target.value;
|
||||||
this.dispatchWizardUpdate({
|
this.dispatchWizardUpdate({
|
||||||
update: {
|
update: {
|
||||||
|
...this.wizard,
|
||||||
provider: {
|
provider: {
|
||||||
|
...this.wizard.provider,
|
||||||
[target.name]: value,
|
[target.name]: value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { consume } from "@lit/context";
|
import { consume } from "@lit-labs/context";
|
||||||
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
|
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
|
||||||
import { state } from "@lit/reactive-element/decorators/state.js";
|
import { state } from "@lit/reactive-element/decorators/state.js";
|
||||||
import { LitElement, html } from "lit";
|
import { LitElement, html } from "lit";
|
||||||
|
|
|
@ -29,7 +29,7 @@ export interface ApplicationWizardState {
|
||||||
type StatusType = "invalid" | "valid" | "submitted" | "failed";
|
type StatusType = "invalid" | "valid" | "submitted" | "failed";
|
||||||
|
|
||||||
export type ApplicationWizardStateUpdate = {
|
export type ApplicationWizardStateUpdate = {
|
||||||
update?: Partial<ApplicationWizardState>;
|
update?: ApplicationWizardState;
|
||||||
status?: StatusType;
|
status?: StatusType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Reference in New Issue