web: application wizard spit & polish

The "ApplicationWizardHint" now correctly uses the localstorage and allows the user to navigate back
and see the message after it's been hidden, so that it will always be available during the test
phase.

The ApplicationList's old "Create Application Form" button has been restored for the purposes of the
test phase.

The ApplicationWizard is now available on both the ApplicationList and ProviderList pages.

Tana and I discussed the microcopy, putting a stronger second-person "You can do..." twist onto the
language, to give the user the sense of empowerment.

The ShowHintController now has both "hide" and "show" operations, to support the hint restoration.
This commit is contained in:
Ken Sternberg 2023-10-17 12:39:42 -07:00
parent b620f19300
commit 1d7fef501d
5 changed files with 64 additions and 41 deletions

View File

@ -1,8 +1,9 @@
import "@goauthentik/admin/applications/ApplicationForm";
import "@goauthentik/admin/applications/wizard/ak-application-wizard";
import "./ApplicationWizardHint";
import { PFSize } from "@goauthentik/app/elements/Spinner";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { uiConfig } from "@goauthentik/common/ui/config";
import { getURLParam } from "@goauthentik/elements/router/RouteMatch";
import "@goauthentik/components/ak-app-icon";
import MDApplication from "@goauthentik/docs/core/applications.md";
import "@goauthentik/elements/Markdown";
@ -33,7 +34,7 @@ export class ApplicationListPage extends TablePage<Application> {
}
pageDescription(): string {
return msg(
"External Applications which use authentik as Identity-Provider, utilizing protocols like OAuth2 and SAML. All applications are shown here, even ones you cannot access.",
"External applications that use authentik as an identity provider via protocols like OAuth2 and SAML. All applications are shown here, even ones you cannot access.",
);
}
pageIcon(): string {
@ -87,6 +88,10 @@ export class ApplicationListPage extends TablePage<Application> {
];
}
renderSectionBefore(): TemplateResult {
return html`<ak-application-wizard-hint></ak-application-wizard-hint>`;
}
renderSidebarAfter(): TemplateResult {
// Rendering the wizard with .open here, as if we set the attribute in
// renderObjectCreate() it'll open two wizards, since that function gets called twice
@ -163,7 +168,6 @@ export class ApplicationListPage extends TablePage<Application> {
];
}
/*
renderObjectCreate(): TemplateResult {
return html`<ak-forms-modal .open=${getURLParam("createForm", false)}>
<span slot="submit"> ${msg("Create")} </span>
@ -172,9 +176,4 @@ export class ApplicationListPage extends TablePage<Application> {
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
</ak-forms-modal>`;
}
*/
renderObjectCreate(): TemplateResult {
return html`<ak-application-wizard></ak-application-wizard>`;
}
}

View File

@ -1,23 +1,31 @@
import { MessageLevel } from "@goauthentik/common/messages";
import {
ShowHintController,
ShowHintControllerHost,
} from "@goauthentik/components/ak-hint/ShowHintController";
import "@goauthentik/admin/applications/wizard/ak-application-wizard";
import { ShowHintController, ShowHintControllerHost } from "@goauthentik/components/ak-hint/ShowHintController";
import "@goauthentik/components/ak-hint/ak-hint";
import "@goauthentik/components/ak-hint/ak-hint-body";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/Label";
import "@goauthentik/elements/buttons/ActionButton/ak-action-button";
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
import { getURLParam } from "@goauthentik/elements/router/RouteMatch";
import { html, nothing } from "lit";
import { msg } from "@lit/localize";
import { html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { styleMap } from "lit/directives/style-map.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFLabel from "@patternfly/patternfly/components/Label/label.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
const closeButtonIcon = html`<svg fill="currentColor" height="1em" width="1em" viewBox="0 0 352 512" aria-hidden="true" role="img" style="vertical-align: -0.125em;">
<path
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
></path>
</svg>`;
@customElement("ak-application-wizard-hint")
export class AkApplicationWizardHint extends AKElement implements ShowHintControllerHost {
static get styles() {
return [PFPage];
return [PFButton, PFPage, PFLabel];
}
@property({ type: Boolean, attribute: "show-hint" })
@ -30,10 +38,21 @@ export class AkApplicationWizardHint extends AKElement implements ShowHintContro
constructor() {
super();
this.showHintController = new ShowHintController(
this,
"202310-application-wizard-announcement",
);
this.showHintController = new ShowHintController(this, "202310-application-wizard-announcement");
}
renderReminder() {
const sectionStyles = { paddingBottom: "0", marginBottom: "-0.5rem", marginRight: "0.0625rem", textAlign: "right" };
const textStyle = { maxWidth: "60ch" };
return html`<section class="pf-c-page__main-section pf-m-no-padding-mobile" style="${styleMap(sectionStyles)}">
<span class="pf-c-label">
<a class="pf-c-label__content" @click=${this.showHintController.show}>
<span class="pf-c-label__text" style="${styleMap(textStyle)}"> ${msg("One hint, 'New Application Wizard', is currently hidden")} </span>
<button aria-disabled="false" aria-label="Restore Application Wizard Hint " class="pf-c-button pf-m-plain" type="button" data-ouia-safe="true">${closeButtonIcon}</button>
</a>
</span>
</section>`;
}
renderHint() {
@ -41,28 +60,19 @@ export class AkApplicationWizardHint extends AKElement implements ShowHintContro
<ak-hint>
<ak-hint-body>
<p>
Authentik has a new Application Wizard that can configure both an
application and its authentication provider at the same time.
<a href="(link to docs)">Learn more about the wizard here.</a>
You can now configure both an application and its authentication provider at the same time with our new Application Wizard.
<!-- <a href="(link to docs)">Learn more about the wizard here.</a> -->
</p>
<ak-action-button
class="pf-m-secondary"
.apiRequest=${() => {
showMessage({
message: "This would have shown the wizard",
level: MessageLevel.success,
});
}}
>Create with Wizard</ak-action-button
></ak-hint-body
>
<ak-application-wizard .open=${getURLParam("createWizard", false)} .showButton=${false}></ak-application-wizard>
</ak-hint-body>
${this.showHintController.render()}
</ak-hint>
</section>`;
}
render() {
return this.showHint || this.forceHint ? this.renderHint() : nothing;
return this.showHint || this.forceHint ? this.renderHint() : this.renderReminder();
}
}

View File

@ -26,7 +26,7 @@ export class ApplicationWizard extends CustomListenerElement(
AkWizard<ApplicationWizardStateUpdate, ApplicationStep>,
) {
constructor() {
super(msg("Create"), msg("New application"), msg("Create a new application"));
super(msg("Create With Wizard"), msg("New application"), msg("Create a new application"));
this.steps = newSteps();
}

View File

@ -5,6 +5,7 @@ import "@goauthentik/admin/providers/proxy/ProxyProviderForm";
import "@goauthentik/admin/providers/radius/RadiusProviderForm";
import "@goauthentik/admin/providers/saml/SAMLProviderForm";
import "@goauthentik/admin/providers/scim/SCIMProviderForm";
import "@goauthentik/admin/applications/ApplicationWizardHint";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { uiConfig } from "@goauthentik/common/ui/config";
import "@goauthentik/elements/buttons/SpinnerButton";
@ -60,6 +61,10 @@ export class ProviderListPage extends TablePage<Provider> {
];
}
renderSectionBefore(): TemplateResult {
return html`<ak-application-wizard-hint></ak-application-wizard-hint>`;
}
renderToolbarSelected(): TemplateResult {
const disabled = this.selectedElements.length < 1;
return html`<ak-forms-delete-bulk

View File

@ -27,18 +27,27 @@ export class ShowHintController implements ReactiveController {
constructor(host: ShowHintControllerHost, hintToken: string) {
(this.host = host).addController(this);
this.hintToken = hintToken;
this.hideTheHint = this.hideTheHint.bind(this);
this.hide = this.hide.bind(this);
this.show = this.show.bind(this);
}
hideTheHint() {
setTheHint(state: boolean = false) {
window?.localStorage.setItem(
LOCALSTORAGE_AUTHENTIK_KEY,
JSON.stringify({
...getCurrentStorageValue(),
[this.hintToken]: false,
[this.hintToken]: state,
}),
);
this.host.showHint = false;
this.host.showHint = state;
}
hide() {
this.setTheHint(false);
}
show() {
this.setTheHint(true);
}
hostConnected() {
@ -54,7 +63,7 @@ export class ShowHintController implements ReactiveController {
render() {
return html`<ak-hint-footer
><div style="text-align: right">
<input type="checkbox" @input=${this.hideTheHint} />${msg(
<input type="checkbox" @input=${this.hide} />${msg(
"Don't show this message again.",
)}
</div></ak-hint-footer