diff --git a/web/src/admin/applications/wizard/ak-application-wizard-application-details.css.ts b/web/src/admin/applications/wizard/ApplicationWizardCss.ts similarity index 100% rename from web/src/admin/applications/wizard/ak-application-wizard-application-details.css.ts rename to web/src/admin/applications/wizard/ApplicationWizardCss.ts diff --git a/web/src/admin/applications/wizard/ApplicationWizardPageBase.ts b/web/src/admin/applications/wizard/ApplicationWizardPageBase.ts index fbf4efa71..bde4b04d9 100644 --- a/web/src/admin/applications/wizard/ApplicationWizardPageBase.ts +++ b/web/src/admin/applications/wizard/ApplicationWizardPageBase.ts @@ -4,8 +4,7 @@ import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter"; import { consume } from "@lit-labs/context"; import { state } from "@lit/reactive-element/decorators/state.js"; -import { styles as AwadStyles } from "./ak-application-wizard-application-details.css"; - +import { styles as AwadStyles } from "./ApplicationWizardCss"; import type { WizardState } from "./ak-application-wizard-context"; import { applicationWizardContext } from "./ak-application-wizard-context-name"; @@ -14,13 +13,12 @@ export class ApplicationWizardPageBase extends CustomEmitterElement(AKElement) { return AwadStyles; } - // @ts-expect-error @consume({ context: applicationWizardContext, subscribe: true }) @state() public wizard!: WizardState; dispatchWizardUpdate(update: Partial) { - this.dispatchCustomEvent("ak-wizard-update", { + this.dispatchCustomEvent("ak-application-wizard-update", { ...this.wizard, ...update, }); diff --git a/web/src/admin/applications/wizard/ApplicationWizardSteps.ts b/web/src/admin/applications/wizard/ApplicationWizardSteps.ts new file mode 100644 index 000000000..078729dd8 --- /dev/null +++ b/web/src/admin/applications/wizard/ApplicationWizardSteps.ts @@ -0,0 +1,43 @@ +import { WizardStep, makeWizardId } from "@goauthentik/components/ak-wizard-main"; +import "./application/ak-application-wizard-application-details"; +import "./auth-method-choice/ak-application-wizard-authentication-method-choice"; +import "./auth-method/ak-application-wizard-authentication-method"; + +import { msg } from "@lit/localize"; +import { html } from "lit"; + +export const steps: WizardStep[] = [ + { + id: makeWizardId("application"), + nextStep: makeWizardId("auth-method-choice"), + label: "Application Details", + renderer: () => + html``, + disabled: false, + nextButtonLabel: msg("Next"), + valid: true, + }, + { + id: makeWizardId("auth-method-choice"), + backStep: makeWizardId("application"), + nextStep: makeWizardId("auth-method"), + label: "Authentication Method", + renderer: () => + html``, + disabled: false, + nextButtonLabel: msg("Next"), + backButtonLabel: msg("Back"), + valid: true, + }, + { + id: makeWizardId("auth-method"), + backStep: makeWizardId("auth-method-choice"), + label: "Authentication Details", + renderer: () => + html``, + disabled: true, + nextButtonLabel: msg("Submit"), + backButtonLabel: msg("Back"), + valid: true, + } +]; diff --git a/web/src/admin/applications/wizard/ak-application-wizard.ts b/web/src/admin/applications/wizard/ak-application-wizard.ts index 586e3e315..9f8d1de84 100644 --- a/web/src/admin/applications/wizard/ak-application-wizard.ts +++ b/web/src/admin/applications/wizard/ak-application-wizard.ts @@ -1,58 +1,43 @@ -import "@goauthentik/admin/applications/wizard/InitialApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/TypeApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/ldap/TypeLDAPApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/link/TypeLinkApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthAPIApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthCodeApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthImplicitApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/proxy/TypeProxyApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/saml/TypeSAMLApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/saml/TypeSAMLConfigApplicationWizardPage"; -import "@goauthentik/admin/applications/wizard/saml/TypeSAMLImportApplicationWizardPage"; +import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter"; +import "@goauthentik/components/ak-wizard-main"; import { AKElement } from "@goauthentik/elements/Base"; -import "@goauthentik/elements/wizard/Wizard"; +import { provide } from "@lit-labs/context"; import { msg } from "@lit/localize"; -import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; import { CSSResult, TemplateResult, html } from "lit"; -import { property } from "lit/decorators.js"; +import { property, customElement, state } from "lit/decorators.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFRadio from "@patternfly/patternfly/components/Radio/radio.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; -/* -const steps = [ - { - name: msg("Application Details"), - view: () => - html``, - }, - { - name: msg("Authentication Method"), - view: () => - html``, - }, - { - name: msg("Authentication Details"), - view: () => - html``, - }, - { - name: msg("Save Application"), - view: () => - html``, - }, - ]; - */ +import { WizardState, WizardStateEvent } from "./types" +import { steps } from "./ApplicationWizardSteps"; +import applicationWizardContext from "./ak-application-wizard-context-name"; + +// my-context.ts @customElement("ak-application-wizard") -export class ApplicationWizard extends AKElement { +export class ApplicationWizard extends CustomListenerElement(AKElement) { static get styles(): CSSResult[] { return [PFBase, PFButton, PFRadio]; } + /** + * Providing a context at the root element + */ + @provide({ context: applicationWizardContext }) + @property({ attribute: false }) + wizardState: WizardState = { + step: 0, + providerType: "", + application: {}, + provider: {}, + }; + + @state() + steps = steps; + @property({ type: Boolean }) open = false; @@ -67,23 +52,54 @@ export class ApplicationWizard extends AKElement { return Promise.resolve(); }; + constructor() { + super(); + this.handleUpdate = this.handleUpdate.bind(this); + } + + connectedCallback() { + super.connectedCallback(); + this.addCustomListener("ak-application-wizard-update", this.handleUpdate); + } + + disconnectedCallback() { + this.removeCustomListener("ak-application-wizard-update", this.handleUpdate); + super.disconnectedCallback(); + } + + // And this is where all the special cases go... + handleUpdate(event: CustomEvent) { + delete event.detail.target; + const newWizardState: WizardState = event.detail; + + // When the user sets the authentication method type, the corresponding authentication + // method page becomes available. + if (newWizardState.providerType !== "") { + const newSteps = [...this.steps]; + const method = newSteps.find(({ id }) => id === "auth-method"); + if (!method) { + throw new Error("Could not find Authentication Method page?"); + } + method.disabled = false; + this.steps = newSteps; + } + + this.wizardState = newWizardState; + } + render(): TemplateResult { return html` - { - return this.finalHandler(); - }} > ${this.showButton ? html`` : html``} - + `; } } diff --git a/web/src/admin/applications/wizard/ak-application-wizard-application-details.ts b/web/src/admin/applications/wizard/application/ak-application-wizard-application-details.ts similarity index 98% rename from web/src/admin/applications/wizard/ak-application-wizard-application-details.ts rename to web/src/admin/applications/wizard/application/ak-application-wizard-application-details.ts index 31cf2823c..0c4d443ef 100644 --- a/web/src/admin/applications/wizard/ak-application-wizard-application-details.ts +++ b/web/src/admin/applications/wizard/application/ak-application-wizard-application-details.ts @@ -12,10 +12,11 @@ import { customElement } from "@lit/reactive-element/decorators/custom-element.j import { TemplateResult, html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; -import ApplicationWizardPageBase from "./ApplicationWizardPageBase"; +import ApplicationWizardPageBase from "../ApplicationWizardPageBase"; @customElement("ak-application-wizard-application-details") export class ApplicationWizardApplicationDetails extends ApplicationWizardPageBase { + handleChange(ev: Event) { if (!ev.target) { console.warn(`Received event with no target: ${ev}`); @@ -88,4 +89,6 @@ export class ApplicationWizardApplicationDetails extends ApplicationWizardPageBa } } + + export default ApplicationWizardApplicationDetails; diff --git a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.choices.ts b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts similarity index 100% rename from web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.choices.ts rename to web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts diff --git a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.ts b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.ts similarity index 91% rename from web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.ts rename to web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.ts index 82ec4ecfb..a868d4e41 100644 --- a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.ts +++ b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.ts @@ -12,7 +12,7 @@ import { map } from "lit/directives/map.js"; import type { TypeCreate } from "@goauthentik/api"; -import ApplicationWizardPageBase from "./ApplicationWizardPageBase"; +import ApplicationWizardPageBase from "../ApplicationWizardPageBase"; import providerTypesList from "./ak-application-wizard-authentication-method-choice.choices"; @customElement("ak-application-wizard-authentication-method-choice") @@ -29,13 +29,16 @@ export class ApplicationWizardAuthenticationMethodChoice extends ApplicationWiza } renderProvider(type: TypeCreate) { + const method = this.wizard.providerType; + return html`
diff --git a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method.ts b/web/src/admin/applications/wizard/auth-method/ak-application-wizard-authentication-method.ts similarity index 56% rename from web/src/admin/applications/wizard/ak-application-wizard-authentication-method.ts rename to web/src/admin/applications/wizard/auth-method/ak-application-wizard-authentication-method.ts index ff6db0417..ab727ba07 100644 --- a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method.ts +++ b/web/src/admin/applications/wizard/auth-method/ak-application-wizard-authentication-method.ts @@ -1,11 +1,11 @@ import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; -import ApplicationWizardPageBase from "./ApplicationWizardPageBase"; -import { providerRendererList } from "./ak-application-wizard-authentication-method-choice.choices"; -import "./ldap/ak-application-wizard-authentication-by-ldap"; -import "./oauth/ak-application-wizard-authentication-by-oauth"; -import "./proxy/ak-application-wizard-authentication-for-reverse-proxy"; -import "./proxy/ak-application-wizard-authentication-for-single-forward-proxy"; +import ApplicationWizardPageBase from "../ApplicationWizardPageBase"; +import { providerRendererList } from "../auth-method-choice/ak-application-wizard-authentication-method-choice.choices"; +import "../ldap/ak-application-wizard-authentication-by-ldap"; +import "../oauth/ak-application-wizard-authentication-by-oauth"; +import "../proxy/ak-application-wizard-authentication-for-reverse-proxy"; +import "../proxy/ak-application-wizard-authentication-for-single-forward-proxy"; // prettier-ignore diff --git a/web/src/admin/applications/wizard/stories/ak-application-wizard-main.stories.ts b/web/src/admin/applications/wizard/stories/ak-application-wizard-main.stories.ts new file mode 100644 index 000000000..76d0f1035 --- /dev/null +++ b/web/src/admin/applications/wizard/stories/ak-application-wizard-main.stories.ts @@ -0,0 +1,54 @@ +import { Meta } from "@storybook/web-components"; + +import { TemplateResult, html } from "lit"; + +import { ApplicationWizard } from "../ak-application-wizard"; +import "../ak-application-wizard"; +import { mockData } from "./mockData"; + +const metadata: Meta = { + title: "Elements / Application Wizard Implementation / Main", + component: "ak-application-wizard", + parameters: { + docs: { + description: { + component: "The first page of the application wizard", + }, + }, + mockData, + }, +}; + +const LIGHT = "pf-t-light"; +function injectTheme() { + setTimeout(() => { + if (!document.body.classList.contains(LIGHT)) { + document.body.classList.add(LIGHT); + } + }); +} + +export default metadata; + +const container = (testItem: TemplateResult) => { + injectTheme(); + return html`
+ + ${testItem} +
`; +}; + +export const MainPage = () => { + return container(html` + > +
+ + `); +}; diff --git a/web/src/admin/applications/wizard/stories/ak-application-wizard.stories.ts b/web/src/admin/applications/wizard/stories/ak-application-wizard.stories.ts deleted file mode 100644 index 41b8a22af..000000000 --- a/web/src/admin/applications/wizard/stories/ak-application-wizard.stories.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { Meta } from "@storybook/web-components"; - -import { TemplateResult, html } from "lit"; - -import "../ak-application-wizard-application-details"; -import AkApplicationWizardApplicationDetails from "../ak-application-wizard-application-details"; -import "../ak-application-wizard-authentication-method-choice"; -import "../ak-application-wizard-context"; -import "../ldap/ak-application-wizard-authentication-by-ldap"; -import "../oauth/ak-application-wizard-authentication-by-oauth"; -import "../proxy/ak-application-wizard-authentication-for-reverse-proxy"; -import "../proxy/ak-application-wizard-authentication-for-single-forward-proxy"; -import "../saml/ak-application-wizard-authentication-by-saml-configuration"; -import "../saml/ak-application-wizard-authentication-by-saml-import"; -import "./ak-application-context-display-for-test"; -import { - dummyAuthenticationFlowsSearch, - dummyAuthorizationFlowsSearch, - dummyCoreGroupsSearch, - dummyCryptoCertsSearch, - dummyHasJwks, - dummyPropertyMappings, - dummyProviderTypesList, - dummySAMLProviderMappings, -} from "./samples"; - -const metadata: Meta = { - title: "Elements / Application Wizard / Page 1", - component: "ak-application-wizard-application-details", - parameters: { - docs: { - description: { - component: "The first page of the application wizard", - }, - }, - mockData: [ - { - url: "/api/v3/providers/all/types/", - method: "GET", - status: 200, - response: dummyProviderTypesList, - }, - { - url: "/api/v3/core/groups/?ordering=name", - method: "GET", - status: 200, - response: dummyCoreGroupsSearch, - }, - - { - url: "/api/v3/crypto/certificatekeypairs/?has_key=true&include_details=false&ordering=name", - method: "GET", - status: 200, - response: dummyCryptoCertsSearch, - }, - { - url: "/api/v3/flows/instances/?designation=authentication&ordering=slug", - method: "GET", - status: 200, - response: dummyAuthenticationFlowsSearch, - }, - { - url: "/api/v3/flows/instances/?designation=authorization&ordering=slug", - method: "GET", - status: 200, - response: dummyAuthorizationFlowsSearch, - }, - { - url: "/api/v3/propertymappings/scope/?ordering=scope_name", - method: "GET", - status: 200, - response: dummyPropertyMappings, - }, - { - url: "/api/v3/sources/oauth/?has_jwks=true&ordering=name", - method: "GET", - status: 200, - response: dummyHasJwks, - }, - { - url: "/api/v3/propertymappings/saml/?ordering=saml_name", - method: "GET", - status: 200, - response: dummySAMLProviderMappings, - }, - - ], - }, -}; - -const LIGHT = "pf-t-light"; -function injectTheme() { - setTimeout(() => { - if (!document.body.classList.contains(LIGHT)) { - document.body.classList.add(LIGHT); - } - }); -} - -export default metadata; - -const container = (testItem: TemplateResult) => { - injectTheme(); - return html`
- - ${testItem} -
`; -}; - -export const DescribeApplication = () => { - return container( - html` - -
- -
`, - ); -}; - -export const ChooseAuthMethod = () => { - return container( - html` - -
- -
`, - ); -}; - -export const ConfigureLdap = () => { - return container( - html` - -
- -
`, - ); -}; - -export const ConfigureOauth2 = () => { - return container( - html` - -
- -
`, - ); -}; - -export const ConfigureReverseProxy = () => { - return container( - html` - -
- -
`, - ); -}; - -export const ConfigureSingleForwardProxy = () => { - return container( - html` - -
- -
`, - ); -}; - -export const ConfigureSamlManually = () => { - return container( - html` - -
- -
`, - ); -}; - - -export const SamlImport = () => { - return container( - html` - -
- -
`, - ); -}; diff --git a/web/src/admin/applications/wizard/stories/mockData.ts b/web/src/admin/applications/wizard/stories/mockData.ts new file mode 100644 index 000000000..3bd5be087 --- /dev/null +++ b/web/src/admin/applications/wizard/stories/mockData.ts @@ -0,0 +1,62 @@ +import { + dummyAuthenticationFlowsSearch, + dummyAuthorizationFlowsSearch, + dummyCoreGroupsSearch, + dummyCryptoCertsSearch, + dummyHasJwks, + dummyPropertyMappings, + dummyProviderTypesList, + dummySAMLProviderMappings, +} from "./samples"; + +export const mockData = [ + { + url: "/api/v3/providers/all/types/", + method: "GET", + status: 200, + response: dummyProviderTypesList, + }, + { + url: "/api/v3/core/groups/?ordering=name", + method: "GET", + status: 200, + response: dummyCoreGroupsSearch, + }, + + { + url: "/api/v3/crypto/certificatekeypairs/?has_key=true&include_details=false&ordering=name", + method: "GET", + status: 200, + response: dummyCryptoCertsSearch, + }, + { + url: "/api/v3/flows/instances/?designation=authentication&ordering=slug", + method: "GET", + status: 200, + response: dummyAuthenticationFlowsSearch, + }, + { + url: "/api/v3/flows/instances/?designation=authorization&ordering=slug", + method: "GET", + status: 200, + response: dummyAuthorizationFlowsSearch, + }, + { + url: "/api/v3/propertymappings/scope/?ordering=scope_name", + method: "GET", + status: 200, + response: dummyPropertyMappings, + }, + { + url: "/api/v3/sources/oauth/?has_jwks=true&ordering=name", + method: "GET", + status: 200, + response: dummyHasJwks, + }, + { + url: "/api/v3/propertymappings/saml/?ordering=saml_name", + method: "GET", + status: 200, + response: dummySAMLProviderMappings, + }, +]; diff --git a/web/src/admin/applications/wizard/types.ts b/web/src/admin/applications/wizard/types.ts new file mode 100644 index 000000000..05f0df578 --- /dev/null +++ b/web/src/admin/applications/wizard/types.ts @@ -0,0 +1,27 @@ +import { + Application, + LDAPProvider, + OAuth2Provider, + ProxyProvider, + RadiusProvider, + SAMLProvider, + SCIMProvider, +} from "@goauthentik/api"; + +export type OneOfProvider = + | Partial + | Partial + | Partial + | Partial + | Partial + | Partial; + +export interface WizardState { + step: number; + providerType: string; + application: Partial; + provider: OneOfProvider; +} + +export type WizardStateEvent = WizardState & { target?: HTMLInputElement }; + diff --git a/web/src/components/ak-wizard-2/ak-wizard-context.ts b/web/src/components/ak-wizard-main/ak-wizard-context.ts similarity index 81% rename from web/src/components/ak-wizard-2/ak-wizard-context.ts rename to web/src/components/ak-wizard-main/ak-wizard-context.ts index 19afc8cca..426683092 100644 --- a/web/src/components/ak-wizard-2/ak-wizard-context.ts +++ b/web/src/components/ak-wizard-main/ak-wizard-context.ts @@ -9,6 +9,15 @@ import { WizardStepEvent, } from "./types"; import { akWizardCurrentStepContextName } from "./akWizardCurrentStepContextName"; import { akWizardStepsContextName } from "./akWizardStepsContextName"; +/** + * AkWizardContext + * + * @element ak-wizard-context + * + * The WizardContext controls the navigation for the wizard. It listens for navigation events from + * the wizard frame and responds with changes to the view, including handling the close button. + * + */ @customElement("ak-wizard-context") export class AkWizardContext extends CustomListenerElement(LitElement) { @@ -39,6 +48,11 @@ export class AkWizardContext extends CustomListenerElement(LitElement) { // Note that we always scan for the valid next step and throw an error if we can't find it. // There should never be a question that the currentStep is a *valid* step. + // + // TODO: Put a phase in there so that the current step can validate the contents asynchronously + // before setting the currentStep. Especially since setting the currentStep triggers a second + // asynchronous event-- scheduling a re-render of everything interested in the currentStep + // object. handleNavigation(event: CustomEvent<{ step: WizardStepId | WizardStepEvent }>) { const requestedStep = event.detail.step; if (!requestedStep) { diff --git a/web/src/components/ak-wizard-2/ak-wizard-2.ts b/web/src/components/ak-wizard-main/ak-wizard-frame.ts similarity index 87% rename from web/src/components/ak-wizard-2/ak-wizard-2.ts rename to web/src/components/ak-wizard-main/ak-wizard-frame.ts index 2ec560d05..70a6f8bf8 100644 --- a/web/src/components/ak-wizard-2/ak-wizard-2.ts +++ b/web/src/components/ak-wizard-main/ak-wizard-frame.ts @@ -1,37 +1,38 @@ import { ModalButton } from "@goauthentik/elements/buttons/ModalButton"; import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter"; +import { consume } from "@lit-labs/context"; import { msg } from "@lit/localize"; import { customElement, property, state } from "@lit/reactive-element/decorators.js"; import { html, nothing } from "lit"; - - import { classMap } from "lit/directives/class-map.js"; -import { consume } from "@lit-labs/context" + import PFWizard from "@patternfly/patternfly/components/Wizard/wizard.css"; -import type { WizardStep } from "./types"; import { akWizardCurrentStepContextName } from "./akWizardCurrentStepContextName"; import { akWizardStepsContextName } from "./akWizardStepsContextName"; +import type { WizardStep } from "./types"; /** - * AKWizard is a container for displaying Wizard pages. + * AKWizardFrame is the main container for displaying Wizard pages. * - * AKWizard is one component of a total Wizard development environment. It provides the header, titled - * navigation sidebar, and bottom row button bar. It takes its cues about what to render from two - * data structure, `this.steps: WizardStep[]`, which lists all the current steps *in order* and + * AKWizardFrame is one component of a total Wizard development environment. It provides the header, + * titled navigation sidebar, and bottom row button bar. It takes its cues about what to render from + * two data structure, `this.steps: WizardStep[]`, which lists all the current steps *in order* and * doesn't care otherwise about their structure, and `this.currentStep: WizardStep` which must be a * _reference_ to a member of `this.steps`. * - * @element ak-wizard-2 + * @element ak-wizard-frame * * @fires ak-wizard-nav - Tell the orchestrator what page the user wishes to move to. This is the * only event that causes this wizard to change its appearance. * + * NOTE: The event name is configurable as an attribute. + * */ -@customElement("ak-wizard-2") -export class AkWizard extends CustomEmitterElement(ModalButton) { +@customElement("ak-wizard-frame") +export class AkWizardFrame extends CustomEmitterElement(ModalButton) { static get styles() { return [...super.styles, PFWizard]; } @@ -48,9 +49,6 @@ export class AkWizard extends CustomEmitterElement(ModalButton) { @property() eventName: string = "ak-wizard-nav"; - @property({ type: Boolean }) - isValid = false; - // @ts-expect-error @consume({ context: akWizardStepsContextName, subscribe: true }) @state() @@ -134,7 +132,7 @@ export class AkWizard extends CustomEmitterElement(ModalButton) { renderFooter() { return html`
-${this.currentStep.nextStep ? this.renderFooterNextButton() : nothing } + ${this.currentStep.nextStep ? this.renderFooterNextButton() : nothing} ${this.currentStep.backStep ? this.renderFooterBackButton() : nothing} ${this.canCancel ? this.renderFooterCancelButton() : nothing}
@@ -175,4 +173,4 @@ ${this.currentStep.nextStep ? this.renderFooterNextButton() : nothing } } } -export default AkWizard; +export default AkWizardFrame; diff --git a/web/src/components/ak-wizard-main/ak-wizard-main.ts b/web/src/components/ak-wizard-main/ak-wizard-main.ts new file mode 100644 index 000000000..905904333 --- /dev/null +++ b/web/src/components/ak-wizard-main/ak-wizard-main.ts @@ -0,0 +1,86 @@ +import { AKElement } from "@goauthentik/elements/Base"; + +import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; +import { html } from "lit"; +import { property } from "lit/decorators.js"; +import { ifDefined } from "lit/directives/if-defined.js"; + +import PFButton from "@patternfly/patternfly/components/Button/button.css"; +import PFRadio from "@patternfly/patternfly/components/Radio/radio.css"; +import PFBase from "@patternfly/patternfly/patternfly-base.css"; + +import "./ak-wizard-frame"; +import "./ak-wizard-context"; +import type { WizardStep } from "./types"; + +/** + * AKWizardMain + * + * @element ak-wizard-main + * + * This is the entry point for the wizard. + * + */ + +@customElement("ak-wizard-main") +export class AkWizardMain extends AKElement { + static get styles() { + return [PFBase, PFButton, PFRadio]; + } + + /** + * The steps of the Wizard. + * + * @attribute + */ + @property({ attribute: false }) + steps: WizardStep[] = []; + + /** + * The text of the button + * + * @attribute + */ + @property({ type: String }) + prompt = "Show Wizard" + + /** + * Mostly a control on the ModalButton that summons the wizard component. + * + * @attribute + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * The text of the header on the wizard, upper bar. + * + * @attribute + */ + @property() + header!: string; + + /** + * The text of the description under the header. + * + * @attribute + */ + @property() + description?: string; + + render() { + return html` + + + + + + `; + } +} + +export default AkWizardMain; diff --git a/web/src/components/ak-wizard-2/akWizardCurrentStepContextName.ts b/web/src/components/ak-wizard-main/akWizardCurrentStepContextName.ts similarity index 100% rename from web/src/components/ak-wizard-2/akWizardCurrentStepContextName.ts rename to web/src/components/ak-wizard-main/akWizardCurrentStepContextName.ts diff --git a/web/src/components/ak-wizard-2/akWizardStepsContextName.ts b/web/src/components/ak-wizard-main/akWizardStepsContextName.ts similarity index 100% rename from web/src/components/ak-wizard-2/akWizardStepsContextName.ts rename to web/src/components/ak-wizard-main/akWizardStepsContextName.ts diff --git a/web/src/components/ak-wizard-main/index.ts b/web/src/components/ak-wizard-main/index.ts new file mode 100644 index 000000000..2d4c1a937 --- /dev/null +++ b/web/src/components/ak-wizard-main/index.ts @@ -0,0 +1,5 @@ +import "./ak-wizard-main"; +import type { WizardStepId, WizardStep } from "./types" +import { makeWizardId } from "./types"; + +export { WizardStepId, WizardStep, makeWizardId }; diff --git a/web/src/components/ak-wizard-2/stories/ak-demo-wizard.ts b/web/src/components/ak-wizard-main/stories/ak-demo-wizard.ts similarity index 75% rename from web/src/components/ak-wizard-2/stories/ak-demo-wizard.ts rename to web/src/components/ak-wizard-main/stories/ak-demo-wizard.ts index e8f9009af..00a58dcb5 100644 --- a/web/src/components/ak-wizard-2/stories/ak-demo-wizard.ts +++ b/web/src/components/ak-wizard-main/stories/ak-demo-wizard.ts @@ -3,13 +3,14 @@ import { AKElement } from "@goauthentik/elements/Base"; import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; import { html } from "lit"; import { property } from "lit/decorators.js"; +import { ifDefined } from "lit/directives/if-defined.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFRadio from "@patternfly/patternfly/components/Radio/radio.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; +import "../ak-wizard-frame"; import "../ak-wizard-context"; -import "../ak-wizard-2"; import type { WizardStep } from "../types"; @customElement("ak-demo-wizard") @@ -24,16 +25,22 @@ export class AkDemoWizard extends AKElement { @property({ type: Boolean }) open = false; + @property() + header!: string; + + @property() + description?: string; + render() { return html` - - + `; } diff --git a/web/src/components/ak-wizard-2/stories/ak-wizard-2.stories.ts b/web/src/components/ak-wizard-main/stories/ak-wizard-main.stories.ts similarity index 83% rename from web/src/components/ak-wizard-2/stories/ak-wizard-2.stories.ts rename to web/src/components/ak-wizard-main/stories/ak-wizard-main.stories.ts index 71c7c0bfc..98d4d4cd6 100644 --- a/web/src/components/ak-wizard-2/stories/ak-wizard-2.stories.ts +++ b/web/src/components/ak-wizard-main/stories/ak-wizard-main.stories.ts @@ -3,16 +3,15 @@ import { Meta } from "@storybook/web-components"; import { TemplateResult, html } from "lit"; -import "../ak-wizard-2" -import "./ak-demo-wizard"; -import AkWizard from "../ak-wizard-2"; +import "../ak-wizard-main" +import AkWizard from "../ak-wizard-main"; import type { WizardStep } from "../types"; import { makeWizardId } from "../types"; const metadata: Meta = { title: "Components / Wizard / Basic", - component: "ak-wizard-2", + component: "ak-wizard-main", parameters: { docs: { description: { @@ -36,8 +35,6 @@ const container = (testItem: TemplateResult) => ${testItem} -

Messages received from the button:

-
    `; @@ -67,6 +64,6 @@ const dummySteps: WizardStep[] = [ export const OnePageWizard = () => { return container( - html` ` + html` ` ); }; diff --git a/web/src/components/ak-wizard-2/types.ts b/web/src/components/ak-wizard-main/types.ts similarity index 87% rename from web/src/components/ak-wizard-2/types.ts rename to web/src/components/ak-wizard-main/types.ts index 272a6fc59..b6f4e725e 100644 --- a/web/src/components/ak-wizard-2/types.ts +++ b/web/src/components/ak-wizard-main/types.ts @@ -18,7 +18,3 @@ export interface WizardStep { backButtonLabel?: string } -export enum WizardStepEvent { - next = "next", - back = "back" -}