web: add visualizing and testing for the FieldRenderers
This commit is contained in:
		
							
								
								
									
										108
									
								
								web/src/flow/stages/prompt/FieldRenderers.stories.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								web/src/flow/stages/prompt/FieldRenderers.stories.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					import { TemplateResult, html } from "lit";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/components/Alert/alert.css";
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/components/Button/button.css";
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/components/Check/check.css";
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/components/Form/form.css";
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/components/Login/login.css";
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/components/Title/title.css";
 | 
				
			||||||
 | 
					import "@patternfly/patternfly/patternfly-base.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { PromptTypeEnum } from "@goauthentik/api";
 | 
				
			||||||
 | 
					import type { StagePrompt } from "@goauthentik/api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import promptRenderers from "./FieldRenderers";
 | 
				
			||||||
 | 
					import { renderContinue, renderPromptHelpText, renderPromptInner } from "./helpers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Storybook stories are meant to show not just that the objects work, but to document good
 | 
				
			||||||
 | 
					// practices around using them.  Because of their uniform signature, the renderers can easily
 | 
				
			||||||
 | 
					// be encapsulated into containers that show them at their most functional, even without
 | 
				
			||||||
 | 
					// building Shadow DOMs with which to do it.  This is 100% Light DOM work, and they still
 | 
				
			||||||
 | 
					// work well.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const baseRenderer = (prompt: TemplateResult) =>
 | 
				
			||||||
 | 
					    html`<div style="background: #fff; padding: 4em; max-width: 24em;">
 | 
				
			||||||
 | 
					        <style>
 | 
				
			||||||
 | 
					            input,
 | 
				
			||||||
 | 
					            textarea,
 | 
				
			||||||
 | 
					            select,
 | 
				
			||||||
 | 
					            button,
 | 
				
			||||||
 | 
					            .pf-c-form__helper-text:not(.pf-m-error),
 | 
				
			||||||
 | 
					            input + label.pf-c-check__label {
 | 
				
			||||||
 | 
					                color: #000;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            input[readonly],
 | 
				
			||||||
 | 
					            textarea[readonly] {
 | 
				
			||||||
 | 
					                color: #fff;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        </style>
 | 
				
			||||||
 | 
					        ${prompt}
 | 
				
			||||||
 | 
					    </div>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function renderer(kind: PromptTypeEnum, prompt: Partial<StagePrompt>) {
 | 
				
			||||||
 | 
					    const renderer = promptRenderers.get(kind);
 | 
				
			||||||
 | 
					    if (!renderer) {
 | 
				
			||||||
 | 
					        throw new Error(`A renderer of type ${kind} does not exist.`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return baseRenderer(html`${renderer(prompt as StagePrompt)}`);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const textPrompt = {
 | 
				
			||||||
 | 
					    fieldKey: "test_text_field",
 | 
				
			||||||
 | 
					    placeholder: "This is the placeholder",
 | 
				
			||||||
 | 
					    required: false,
 | 
				
			||||||
 | 
					    initialValue: "initial value",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Text = () => renderer(PromptTypeEnum.Text, textPrompt);
 | 
				
			||||||
 | 
					export const TextArea = () => renderer(PromptTypeEnum.TextArea, textPrompt);
 | 
				
			||||||
 | 
					export const TextReadOnly = () => renderer(PromptTypeEnum.TextReadOnly, textPrompt);
 | 
				
			||||||
 | 
					export const TextAreaReadOnly = () => renderer(PromptTypeEnum.TextAreaReadOnly, textPrompt);
 | 
				
			||||||
 | 
					export const Username = () => renderer(PromptTypeEnum.Username, textPrompt);
 | 
				
			||||||
 | 
					export const Password = () => renderer(PromptTypeEnum.Password, textPrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emailPrompt = { ...textPrompt, initialValue: "example@example.fun" };
 | 
				
			||||||
 | 
					export const Email = () => renderer(PromptTypeEnum.Email, emailPrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const numberPrompt = { ...textPrompt, initialValue: "10" };
 | 
				
			||||||
 | 
					export const Number = () => renderer(PromptTypeEnum.Number, numberPrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const datePrompt = { ...textPrompt, initialValue: "2018-06-12T19:30" };
 | 
				
			||||||
 | 
					export const Date = () => renderer(PromptTypeEnum.Date, datePrompt);
 | 
				
			||||||
 | 
					export const DateTime = () => renderer(PromptTypeEnum.DateTime, datePrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const separatorPrompt = { placeholder: "😊" };
 | 
				
			||||||
 | 
					export const Separator = () => renderer(PromptTypeEnum.Separator, separatorPrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const staticPrompt = { initialValue: "😊" };
 | 
				
			||||||
 | 
					export const Static = () => renderer(PromptTypeEnum.Static, staticPrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const choicePrompt = {
 | 
				
			||||||
 | 
					    fieldKey: "test_text_field",
 | 
				
			||||||
 | 
					    placeholder: "This is the placeholder",
 | 
				
			||||||
 | 
					    required: false,
 | 
				
			||||||
 | 
					    initialValue: "first",
 | 
				
			||||||
 | 
					    choices: ["first", "second", "third"],
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Dropdown = () => renderer(PromptTypeEnum.Dropdown, choicePrompt);
 | 
				
			||||||
 | 
					export const RadioButtonGroup = () => renderer(PromptTypeEnum.RadioButtonGroup, choicePrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const checkPrompt = { ...textPrompt, label: "Favorite Subtext?", subText: "(Xena & Gabrielle)" };
 | 
				
			||||||
 | 
					export const Checkbox = () => renderer(PromptTypeEnum.Checkbox, checkPrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const localePrompt = { ...textPrompt, initialValue: "en" };
 | 
				
			||||||
 | 
					export const Locale = () => renderer(PromptTypeEnum.AkLocale, localePrompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const PromptFailure = () =>
 | 
				
			||||||
 | 
					    baseRenderer(renderPromptInner({ type: null } as unknown as StagePrompt));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const HelpText = () =>
 | 
				
			||||||
 | 
					    baseRenderer(renderPromptHelpText({ subText: "There is no subtext here." } as StagePrompt));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Continue = () => baseRenderer(renderContinue());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					    title: "Flow Components/Field Renderers",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -207,6 +207,24 @@ export function renderRadioButtonGroup(prompt: StagePrompt) {
 | 
				
			|||||||
    })}`;
 | 
					    })}`;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function renderCheckbox(prompt: StagePrompt) {
 | 
				
			||||||
 | 
					    return html`<div class="pf-c-check">
 | 
				
			||||||
 | 
					        <input
 | 
				
			||||||
 | 
					            type="checkbox"
 | 
				
			||||||
 | 
					            class="pf-c-check__input"
 | 
				
			||||||
 | 
					            id="${prompt.fieldKey}"
 | 
				
			||||||
 | 
					            name="${prompt.fieldKey}"
 | 
				
			||||||
 | 
					            ?checked=${prompt.initialValue !== ""}
 | 
				
			||||||
 | 
					            ?required=${prompt.required}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <label class="pf-c-check__label" for="${prompt.fieldKey}">${prompt.label}</label>
 | 
				
			||||||
 | 
					        ${prompt.required
 | 
				
			||||||
 | 
					            ? html`<p class="pf-c-form__helper-text">${msg("Required.")}</p>`
 | 
				
			||||||
 | 
					            : html``}
 | 
				
			||||||
 | 
					        <p class="pf-c-form__helper-text">${unsafeHTML(prompt.subText)}</p>
 | 
				
			||||||
 | 
					    </div>`;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function renderAkLocale(prompt: StagePrompt) {
 | 
					export function renderAkLocale(prompt: StagePrompt) {
 | 
				
			||||||
    // TODO: External reference.
 | 
					    // TODO: External reference.
 | 
				
			||||||
    const inDebug = rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanDebug);
 | 
					    const inDebug = rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.CanDebug);
 | 
				
			||||||
@ -247,6 +265,7 @@ export const promptRenderers = new Map<PromptTypeEnum, Renderer>([
 | 
				
			|||||||
    [PromptTypeEnum.Static, renderStatic],
 | 
					    [PromptTypeEnum.Static, renderStatic],
 | 
				
			||||||
    [PromptTypeEnum.Dropdown, renderDropdown],
 | 
					    [PromptTypeEnum.Dropdown, renderDropdown],
 | 
				
			||||||
    [PromptTypeEnum.RadioButtonGroup, renderRadioButtonGroup],
 | 
					    [PromptTypeEnum.RadioButtonGroup, renderRadioButtonGroup],
 | 
				
			||||||
 | 
					    [PromptTypeEnum.Checkbox, renderCheckbox],
 | 
				
			||||||
    [PromptTypeEnum.AkLocale, renderAkLocale],
 | 
					    [PromptTypeEnum.AkLocale, renderAkLocale],
 | 
				
			||||||
]);
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,6 @@ import { BaseStage } from "@goauthentik/flow/stages/base";
 | 
				
			|||||||
import { msg } from "@lit/localize";
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
import { CSSResult, TemplateResult, css, html } from "lit";
 | 
					import { CSSResult, TemplateResult, css, html } from "lit";
 | 
				
			||||||
import { customElement } from "lit/decorators.js";
 | 
					import { customElement } from "lit/decorators.js";
 | 
				
			||||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
 | 
					import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
 | 
				
			||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
					import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
				
			||||||
@ -24,7 +23,13 @@ import {
 | 
				
			|||||||
    StagePrompt,
 | 
					    StagePrompt,
 | 
				
			||||||
} from "@goauthentik/api";
 | 
					} from "@goauthentik/api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import promptRenderers from "./FieldRenderers";
 | 
					import { renderCheckbox } from "./FieldRenderers";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    renderContinue,
 | 
				
			||||||
 | 
					    renderPromptHelpText,
 | 
				
			||||||
 | 
					    renderPromptInner,
 | 
				
			||||||
 | 
					    shouldRenderInWrapper,
 | 
				
			||||||
 | 
					} from "./helpers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@customElement("ak-stage-prompt")
 | 
					@customElement("ak-stage-prompt")
 | 
				
			||||||
export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeResponseRequest> {
 | 
					export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeResponseRequest> {
 | 
				
			||||||
@ -48,70 +53,35 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
 | 
				
			|||||||
        ];
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderPromptInner(prompt: StagePrompt): TemplateResult {
 | 
					    /* TODO: Legacy: None of these refer to the `this` field. Static fields are a code smell. */
 | 
				
			||||||
        const renderer = promptRenderers.get(prompt.type);
 | 
					 | 
				
			||||||
        if (!renderer) {
 | 
					 | 
				
			||||||
            return html`<p>invalid type '${prompt.type}'</p>`;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return renderer(prompt);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderPromptHelpText(prompt: StagePrompt): TemplateResult {
 | 
					    renderPromptInner(prompt: StagePrompt) {
 | 
				
			||||||
        if (prompt.subText === "") {
 | 
					        return renderPromptInner(prompt);
 | 
				
			||||||
            return html``;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return html`<p class="pf-c-form__helper-text">${unsafeHTML(prompt.subText)}</p>`;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    renderPromptHelpText(prompt: StagePrompt) {
 | 
				
			||||||
    shouldRenderInWrapper(prompt: StagePrompt): boolean {
 | 
					        return renderPromptHelpText(prompt);
 | 
				
			||||||
        // Special types that aren't rendered in a wrapper
 | 
					    }
 | 
				
			||||||
        const specialTypes = [
 | 
					    shouldRenderInWrapper(prompt: StagePrompt) {
 | 
				
			||||||
            PromptTypeEnum.Static,
 | 
					        return shouldRenderInWrapper(prompt);
 | 
				
			||||||
            PromptTypeEnum.Hidden,
 | 
					 | 
				
			||||||
            PromptTypeEnum.Separator,
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
        const special = specialTypes.find((s) => s === prompt.type);
 | 
					 | 
				
			||||||
        return !special;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderField(prompt: StagePrompt): TemplateResult {
 | 
					    renderField(prompt: StagePrompt): TemplateResult {
 | 
				
			||||||
        // Checkbox is rendered differently
 | 
					        // Checkbox has a slightly different layout, so it must be intercepted early.
 | 
				
			||||||
        if (prompt.type === PromptTypeEnum.Checkbox) {
 | 
					        if (prompt.type === PromptTypeEnum.Checkbox) {
 | 
				
			||||||
            return html`<div class="pf-c-check">
 | 
					            return renderCheckbox(prompt);
 | 
				
			||||||
                <input
 | 
					 | 
				
			||||||
                    type="checkbox"
 | 
					 | 
				
			||||||
                    class="pf-c-check__input"
 | 
					 | 
				
			||||||
                    id="${prompt.fieldKey}"
 | 
					 | 
				
			||||||
                    name="${prompt.fieldKey}"
 | 
					 | 
				
			||||||
                    ?checked=${prompt.initialValue !== ""}
 | 
					 | 
				
			||||||
                    ?required=${prompt.required}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <label class="pf-c-check__label" for="${prompt.fieldKey}">${prompt.label}</label>
 | 
					 | 
				
			||||||
                ${prompt.required
 | 
					 | 
				
			||||||
                    ? html`<p class="pf-c-form__helper-text">${msg("Required.")}</p>`
 | 
					 | 
				
			||||||
                    : html``}
 | 
					 | 
				
			||||||
                <p class="pf-c-form__helper-text">${unsafeHTML(prompt.subText)}</p>
 | 
					 | 
				
			||||||
            </div>`;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (this.shouldRenderInWrapper(prompt)) {
 | 
					
 | 
				
			||||||
 | 
					        if (shouldRenderInWrapper(prompt)) {
 | 
				
			||||||
            return html`<ak-form-element
 | 
					            return html`<ak-form-element
 | 
				
			||||||
                label="${prompt.label}"
 | 
					                label="${prompt.label}"
 | 
				
			||||||
                ?required="${prompt.required}"
 | 
					                ?required="${prompt.required}"
 | 
				
			||||||
                class="pf-c-form__group"
 | 
					                class="pf-c-form__group"
 | 
				
			||||||
                .errors=${(this.challenge?.responseErrors || {})[prompt.fieldKey]}
 | 
					                .errors=${(this.challenge?.responseErrors || {})[prompt.fieldKey]}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
                ${this.renderPromptInner(prompt)} ${this.renderPromptHelpText(prompt)}
 | 
					                ${renderPromptInner(prompt)} ${renderPromptHelpText(prompt)}
 | 
				
			||||||
            </ak-form-element>`;
 | 
					            </ak-form-element>`;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return html` ${this.renderPromptInner(prompt)} ${this.renderPromptHelpText(prompt)}`;
 | 
					        return html` ${renderPromptInner(prompt)} ${renderPromptHelpText(prompt)}`;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    renderContinue(): TemplateResult {
 | 
					 | 
				
			||||||
        return html` <div class="pf-c-form__group pf-m-action">
 | 
					 | 
				
			||||||
            <button type="submit" class="pf-c-button pf-m-primary pf-m-block">
 | 
					 | 
				
			||||||
                ${msg("Continue")}
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
        </div>`;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render(): TemplateResult {
 | 
					    render(): TemplateResult {
 | 
				
			||||||
@ -119,6 +89,7 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
 | 
				
			|||||||
            return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
 | 
					            return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
 | 
				
			||||||
            </ak-empty-state>`;
 | 
					            </ak-empty-state>`;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return html`<header class="pf-c-login__main-header">
 | 
					        return html`<header class="pf-c-login__main-header">
 | 
				
			||||||
                <h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
 | 
					                <h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
 | 
				
			||||||
            </header>
 | 
					            </header>
 | 
				
			||||||
@ -137,7 +108,7 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
 | 
				
			|||||||
                              this.challenge?.responseErrors?.non_field_errors || [],
 | 
					                              this.challenge?.responseErrors?.non_field_errors || [],
 | 
				
			||||||
                          )
 | 
					                          )
 | 
				
			||||||
                        : html``}
 | 
					                        : html``}
 | 
				
			||||||
                    ${this.renderContinue()}
 | 
					                    ${renderContinue()}
 | 
				
			||||||
                </form>
 | 
					                </form>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <footer class="pf-c-login__main-footer">
 | 
					            <footer class="pf-c-login__main-footer">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										37
									
								
								web/src/flow/stages/prompt/helpers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								web/src/flow/stages/prompt/helpers.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
 | 
					import { html } from "lit";
 | 
				
			||||||
 | 
					import { unsafeHTML } from "lit/directives/unsafe-html.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { PromptTypeEnum, StagePrompt } from "@goauthentik/api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import promptRenderers from "./FieldRenderers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function renderPromptInner(prompt: StagePrompt) {
 | 
				
			||||||
 | 
					    const renderer = promptRenderers.get(prompt.type);
 | 
				
			||||||
 | 
					    if (!renderer) {
 | 
				
			||||||
 | 
					        return html`<p>invalid type '${JSON.stringify(prompt.type, null, 2)}'</p>`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return renderer(prompt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function renderPromptHelpText(prompt: StagePrompt) {
 | 
				
			||||||
 | 
					    if (prompt.subText === "") {
 | 
				
			||||||
 | 
					        return html``;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return html`<p class="pf-c-form__helper-text">${unsafeHTML(prompt.subText)}</p>`;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function shouldRenderInWrapper(prompt: StagePrompt) {
 | 
				
			||||||
 | 
					    // Special types that aren't rendered in a wrapper
 | 
				
			||||||
 | 
					    const specialTypes = [PromptTypeEnum.Static, PromptTypeEnum.Hidden, PromptTypeEnum.Separator];
 | 
				
			||||||
 | 
					    const special = specialTypes.find((s) => s === prompt.type);
 | 
				
			||||||
 | 
					    return !special;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function renderContinue() {
 | 
				
			||||||
 | 
					    return html` <div class="pf-c-form__group pf-m-action">
 | 
				
			||||||
 | 
					        <button type="submit" class="pf-c-button pf-m-primary pf-m-block">
 | 
				
			||||||
 | 
					            ${msg("Continue")}
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					    </div>`;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user