Skip to content

Commit 3d2bd4d

Browse files
authored
web: Fix issues surrounding wizard step behavior. (#12779)
This resolves a few stateful situations which may arise when opening and closing wizard pages.
1 parent 46a968d commit 3d2bd4d

File tree

6 files changed

+287
-138
lines changed

6 files changed

+287
-138
lines changed

web/src/admin/policies/PolicyWizard.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ export class PolicyWizard extends AKElement {
5252
});
5353
}
5454

55+
selectListener = ({ detail }: CustomEvent<TypeCreate>) => {
56+
if (!this.wizard) return;
57+
58+
const { component, modelName } = detail;
59+
const idx = this.wizard.steps.indexOf("initial") + 1;
60+
61+
// Exclude all current steps starting with type-,
62+
// this happens when the user selects a type and then goes back
63+
this.wizard.steps = this.wizard.steps.filter((step) => !step.startsWith("type-"));
64+
65+
this.wizard.steps.splice(idx, 0, `type-${component}-${modelName}`);
66+
67+
this.wizard.isValid = true;
68+
};
69+
5570
render(): TemplateResult {
5671
return html`
5772
<ak-wizard
@@ -62,23 +77,10 @@ export class PolicyWizard extends AKElement {
6277
<ak-wizard-page-type-create
6378
slot="initial"
6479
.types=${this.policyTypes}
65-
@select=${(ev: CustomEvent<TypeCreate>) => {
66-
if (!this.wizard) return;
67-
const idx = this.wizard.steps.indexOf("initial") + 1;
68-
// Exclude all current steps starting with type-,
69-
// this happens when the user selects a type and then goes back
70-
this.wizard.steps = this.wizard.steps.filter(
71-
(step) => !step.startsWith("type-"),
72-
);
73-
this.wizard.steps.splice(
74-
idx,
75-
0,
76-
`type-${ev.detail.component}-${ev.detail.modelName}`,
77-
);
78-
this.wizard.isValid = true;
79-
}}
80+
@select=${this.selectListener}
8081
>
8182
</ak-wizard-page-type-create>
83+
8284
${this.policyTypes.map((type) => {
8385
return html`
8486
<ak-wizard-page-form

web/src/elements/wizard/ActionWizardPage.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,20 @@ export class ActionWizardPage extends WizardPage {
4141

4242
activeCallback = async (): Promise<void> => {
4343
this.states = [];
44+
4445
this.host.actions.map((act, idx) => {
4546
this.states.push({
4647
action: act,
4748
state: ActionState.pending,
4849
idx: idx,
4950
});
5051
});
52+
5153
this.host.canBack = false;
5254
this.host.canCancel = false;
55+
5356
await this.run();
57+
5458
// Ensure wizard is closable, even when run() failed
5559
this.host.isValid = true;
5660
};
@@ -59,28 +63,37 @@ export class ActionWizardPage extends WizardPage {
5963

6064
async run(): Promise<void> {
6165
this.currentStep = this.states[0];
66+
6267
await new Promise((r) => setTimeout(r, 500));
68+
6369
for await (const bundle of this.states) {
6470
this.currentStep = bundle;
6571
this.currentStep.state = ActionState.running;
6672
this.requestUpdate();
6773
try {
6874
await bundle.action.run();
75+
6976
await new Promise((r) => setTimeout(r, 500));
77+
7078
this.currentStep.state = ActionState.done;
79+
7180
this.requestUpdate();
7281
} catch (exc) {
7382
if (exc instanceof ResponseError) {
7483
this.currentStep.action.subText = await exc.response.text();
7584
} else {
7685
this.currentStep.action.subText = (exc as Error).toString();
7786
}
87+
7888
this.currentStep.state = ActionState.failed;
7989
this.requestUpdate();
90+
8091
return;
8192
}
8293
}
94+
8395
this.host.isValid = true;
96+
8497
this.dispatchEvent(
8598
new CustomEvent(EVENT_REFRESH, {
8699
bubbles: true,

web/src/elements/wizard/TypeCreateWizardPage.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
55
import { msg, str } from "@lit/localize";
66
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
77
import { customElement, property } from "lit/decorators.js";
8+
import { Ref, createRef, ref } from "lit/directives/ref.js";
89

910
import PFCard from "@patternfly/patternfly/components/Card/card.css";
1011
import PFForm from "@patternfly/patternfly/components/Form/form.css";
@@ -21,6 +22,8 @@ export enum TypeCreateWizardPageLayouts {
2122

2223
@customElement("ak-wizard-page-type-create")
2324
export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
25+
//#region Properties
26+
2427
@property({ attribute: false })
2528
types: TypeCreate[] = [];
2629

@@ -30,6 +33,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
3033
@property({ type: String })
3134
layout: TypeCreateWizardPageLayouts = TypeCreateWizardPageLayouts.list;
3235

36+
//#endregion
37+
3338
static get styles(): CSSResult[] {
3439
return [
3540
PFBase,
@@ -49,10 +54,25 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
4954
];
5055
}
5156

52-
sidebarLabel = () => msg("Select type");
57+
//#region Refs
58+
59+
formRef: Ref<HTMLFormElement> = createRef();
60+
61+
//#endregion
62+
63+
public sidebarLabel = () => msg("Select type");
64+
65+
public reset = () => {
66+
super.reset();
67+
this.selectedType = undefined;
68+
this.formRef.value?.reset();
69+
};
70+
71+
activeCallback = (): void => {
72+
const form = this.formRef.value;
73+
74+
this.host.isValid = form?.checkValidity() ?? false;
5375

54-
activeCallback: () => Promise<void> = async () => {
55-
this.host.isValid = false;
5676
if (this.selectedType) {
5777
this.selectDispatch(this.selectedType);
5878
}
@@ -92,9 +112,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
92112
data-ouid-component-type="ak-type-create-grid-card"
93113
data-ouid-component-name=${componentName}
94114
@click=${() => {
95-
if (requiresEnterprise) {
96-
return;
97-
}
115+
if (requiresEnterprise) return;
116+
98117
this.selectDispatch(type);
99118
this.selectedType = type;
100119
}}
@@ -120,11 +139,13 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
120139

121140
renderList(): TemplateResult {
122141
return html`<form
142+
${ref(this.formRef)}
123143
class="pf-c-form pf-m-horizontal"
124144
data-ouid-component-type="ak-type-create-list"
125145
>
126146
${this.types.map((type) => {
127147
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
148+
128149
return html`<div
129150
class="pf-c-radio"
130151
data-ouid-component-type="ak-type-create-list-card"
@@ -160,6 +181,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
160181
return this.renderGrid();
161182
case TypeCreateWizardPageLayouts.list:
162183
return this.renderList();
184+
default:
185+
throw new Error(`Unknown layout: ${this.layout}`) as never;
163186
}
164187
}
165188
}

0 commit comments

Comments
 (0)