diff --git a/authentik/core/templates/if/admin.html b/authentik/core/templates/if/admin.html
index 243772a85..43df9a509 100644
--- a/authentik/core/templates/if/admin.html
+++ b/authentik/core/templates/if/admin.html
@@ -3,7 +3,7 @@
{% load static %}
{% block head %}
-
+
{% endblock %}
{% block body %}
diff --git a/authentik/core/templates/if/flow.html b/authentik/core/templates/if/flow.html
index 0197da38d..3756f4f89 100644
--- a/authentik/core/templates/if/flow.html
+++ b/authentik/core/templates/if/flow.html
@@ -3,7 +3,7 @@
{% load static %}
{% block head %}
-
+
{% endblock %}
{% block body %}
diff --git a/authentik/flows/tests/test_views.py b/authentik/flows/tests/test_views.py
index 7c4f294ff..6664ea28f 100644
--- a/authentik/flows/tests/test_views.py
+++ b/authentik/flows/tests/test_views.py
@@ -416,7 +416,7 @@ class TestFlowExecutor(TestCase):
{
"background": flow.background.url,
"type": ChallengeTypes.native.value,
- "component": "",
+ "component": "ak-stage-dummy",
"title": binding.stage.name,
},
)
diff --git a/authentik/root/messages/storage.py b/authentik/root/messages/storage.py
index 0999c276c..4e23ca729 100644
--- a/authentik/root/messages/storage.py
+++ b/authentik/root/messages/storage.py
@@ -25,7 +25,7 @@ class ChannelsStorage(FallbackStorage):
uid,
{
"type": "event.update",
- "level_tag": message.level_tag,
+ "level": message.level_tag,
"tags": message.tags,
"message": message.message,
},
diff --git a/authentik/stages/dummy/stage.py b/authentik/stages/dummy/stage.py
index 10f5ad3ca..b4c2f844c 100644
--- a/authentik/stages/dummy/stage.py
+++ b/authentik/stages/dummy/stage.py
@@ -25,7 +25,7 @@ class DummyStageView(ChallengeStageView):
return DummyChallenge(
data={
"type": ChallengeTypes.native.value,
- "component": "",
+ "component": "ak-stage-dummy",
"title": self.executor.current_stage.name,
}
)
diff --git a/web/rollup.config.js b/web/rollup.config.js
index e86f10842..84045077d 100644
--- a/web/rollup.config.js
+++ b/web/rollup.config.js
@@ -65,7 +65,7 @@ export default [
},
// Main Application
{
- input: "./src/main.ts",
+ input: "./src/interfaces/AdminInterface.ts",
output: [
{
format: "es",
@@ -92,7 +92,7 @@ export default [
},
// Flow executor
{
- input: "./src/flow.ts",
+ input: "./src/interfaces/FlowInterface.ts",
output: [
{
format: "es",
diff --git a/web/src/api/Config.ts b/web/src/api/Config.ts
index 10a96aa27..71dba42a0 100644
--- a/web/src/api/Config.ts
+++ b/web/src/api/Config.ts
@@ -4,7 +4,8 @@ import { VERSION } from "../constants";
import { SentryIgnoredError } from "../common/errors";
import { Config, Configuration, RootApi } from "authentik-api";
import { getCookie } from "../utils";
-import { MIDDLEWARE } from "../elements/notifications/APIDrawer";
+import { API_DRAWER_MIDDLEWARE } from "../elements/notifications/APIDrawer";
+import { MessageMiddleware } from "../elements/messages/Middleware";
export const DEFAULT_CONFIG = new Configuration({
basePath: "/api/v2beta",
@@ -13,7 +14,8 @@ export const DEFAULT_CONFIG = new Configuration({
"X-Authentik-Prevent-Basic": "true"
},
middleware: [
- MIDDLEWARE
+ API_DRAWER_MIDDLEWARE,
+ new MessageMiddleware(),
],
});
diff --git a/web/src/api/legacy.ts b/web/src/api/legacy.ts
index b24dfb43e..76808ada8 100644
--- a/web/src/api/legacy.ts
+++ b/web/src/api/legacy.ts
@@ -113,4 +113,8 @@ export class FlowURLManager {
return `/flows/-/configure/${stageUuid}/${rest}`;
}
+ static cancel(): string {
+ return "/flows/-/cancel/";
+ }
+
}
diff --git a/web/src/elements/buttons/ActionButton.ts b/web/src/elements/buttons/ActionButton.ts
index 868c99b36..6e3826f01 100644
--- a/web/src/elements/buttons/ActionButton.ts
+++ b/web/src/elements/buttons/ActionButton.ts
@@ -2,6 +2,7 @@ import { customElement, property } from "lit-element";
import { ERROR_CLASS, SUCCESS_CLASS } from "../../constants";
import { SpinnerButton } from "./SpinnerButton";
import { showMessage } from "../messages/MessageContainer";
+import { MessageLevel } from "../messages/Message";
@customElement("ak-action-button")
export class ActionButton extends SpinnerButton {
@@ -26,13 +27,13 @@ export class ActionButton extends SpinnerButton {
.catch((e: Error | Response) => {
if (e instanceof Error) {
showMessage({
- level_tag: "error",
+ level: MessageLevel.error,
message: e.toString()
});
} else {
e.text().then(t => {
showMessage({
- level_tag: "error",
+ level: MessageLevel.error,
message: t
});
});
diff --git a/web/src/elements/buttons/ModalButton.ts b/web/src/elements/buttons/ModalButton.ts
index 111fc0d04..34061b451 100644
--- a/web/src/elements/buttons/ModalButton.ts
+++ b/web/src/elements/buttons/ModalButton.ts
@@ -19,6 +19,7 @@ import { convertToSlug } from "../../utils";
import { SpinnerButton } from "./SpinnerButton";
import { PRIMARY_CLASS, EVENT_REFRESH } from "../../constants";
import { showMessage } from "../messages/MessageContainer";
+import { MessageLevel } from "../messages/Message";
@customElement("ak-modal-button")
export class ModalButton extends LitElement {
@@ -122,7 +123,7 @@ export class ModalButton extends LitElement {
})
.catch((e) => {
showMessage({
- level_tag: "error",
+ level: MessageLevel.error,
message: "Unexpected error"
});
console.error(e);
@@ -150,7 +151,7 @@ export class ModalButton extends LitElement {
})
.catch((e) => {
showMessage({
- level_tag: "error",
+ level: MessageLevel.error,
message: "Unexpected error"
});
console.error(e);
diff --git a/web/src/elements/forms/ConfirmationForm.ts b/web/src/elements/forms/ConfirmationForm.ts
index edc2dbf55..0bfdfd3b2 100644
--- a/web/src/elements/forms/ConfirmationForm.ts
+++ b/web/src/elements/forms/ConfirmationForm.ts
@@ -2,6 +2,7 @@ import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { EVENT_REFRESH } from "../../constants";
import { ModalButton } from "../buttons/ModalButton";
+import { MessageLevel } from "../messages/Message";
import { showMessage } from "../messages/MessageContainer";
@customElement("ak-forms-confirm")
@@ -36,14 +37,14 @@ export class ConfirmationForm extends ModalButton {
onSuccess(): void {
showMessage({
message: gettext(this.successMessage),
- level_tag: "success",
+ level: MessageLevel.success,
});
}
onError(e: Error): void {
showMessage({
message: gettext(`${this.errorMessage}: ${e.toString()}`),
- level_tag: "error",
+ level: MessageLevel.error,
});
}
diff --git a/web/src/elements/forms/DeleteForm.ts b/web/src/elements/forms/DeleteForm.ts
index 7fbce8d8e..45c1e8d09 100644
--- a/web/src/elements/forms/DeleteForm.ts
+++ b/web/src/elements/forms/DeleteForm.ts
@@ -2,6 +2,7 @@ import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { EVENT_REFRESH } from "../../constants";
import { ModalButton } from "../buttons/ModalButton";
+import { MessageLevel } from "../messages/Message";
import { showMessage } from "../messages/MessageContainer";
@customElement("ak-forms-delete")
@@ -34,14 +35,14 @@ export class DeleteForm extends ModalButton {
onSuccess(): void {
showMessage({
message: gettext(`Successfully deleted ${this.objectLabel} ${ this.obj?.name }`),
- level_tag: "success",
+ level: MessageLevel.success,
});
}
onError(e: Error): void {
showMessage({
message: gettext(`Failed to delete ${this.objectLabel}: ${e.toString()}`),
- level_tag: "error",
+ level: MessageLevel.error,
});
}
diff --git a/web/src/elements/messages/Message.ts b/web/src/elements/messages/Message.ts
index 1c215f190..f4e0bf60e 100644
--- a/web/src/elements/messages/Message.ts
+++ b/web/src/elements/messages/Message.ts
@@ -5,10 +5,17 @@ import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
+export enum MessageLevel {
+ error = "error",
+ warning = "warning",
+ success = "success",
+ info = "info"
+}
export interface APIMessage {
- level_tag: string;
+ level: MessageLevel;
tags?: string;
message: string;
+ description?: string;
}
const LEVEL_ICON_MAP: { [key: string]: string } = {
@@ -44,13 +51,16 @@ export class Message extends LitElement {
render(): TemplateResult {
return html`
-
+
-
+
${this.message?.message}
+ ${this.message?.description && html`
+
${this.message.description}
+
`}
{
if (!this.message) return;
diff --git a/web/src/elements/messages/MessageContainer.ts b/web/src/elements/messages/MessageContainer.ts
index 0588f13a8..b4f6d2db2 100644
--- a/web/src/elements/messages/MessageContainer.ts
+++ b/web/src/elements/messages/MessageContainer.ts
@@ -1,7 +1,7 @@
import { gettext } from "django";
import { LitElement, html, customElement, TemplateResult, property, CSSResult, css } from "lit-element";
import "./Message";
-import { APIMessage } from "./Message";
+import { APIMessage, MessageLevel } from "./Message";
import PFAlertGroup from "@patternfly/patternfly/components/AlertGroup/alert-group.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@@ -63,7 +63,7 @@ export class MessageContainer extends LitElement {
console.debug(`authentik/messages: closed ws connection: ${e}`);
if (this.retryDelay > 3000) {
showMessage({
- level_tag: "error",
+ level: MessageLevel.error,
message: gettext("Connection error, reconnecting...")
});
}
diff --git a/web/src/elements/messages/Middleware.ts b/web/src/elements/messages/Middleware.ts
new file mode 100644
index 000000000..b01861950
--- /dev/null
+++ b/web/src/elements/messages/Middleware.ts
@@ -0,0 +1,18 @@
+import { Middleware, ResponseContext } from "authentik-api";
+import { gettext } from "django";
+import { MessageLevel } from "./Message";
+import { showMessage } from "./MessageContainer";
+
+export class MessageMiddleware implements Middleware {
+
+ post(context: ResponseContext): Promise {
+ if (!context.response.ok) {
+ showMessage({
+ level: MessageLevel.error,
+ message: gettext("API request failed"),
+ description: `${context.init.method} ${context.url}: ${context.response.status}`
+ });
+ }
+ return Promise.resolve(context.response);
+ }
+}
diff --git a/web/src/elements/notifications/APIDrawer.ts b/web/src/elements/notifications/APIDrawer.ts
index 7134b6dee..74d2db018 100644
--- a/web/src/elements/notifications/APIDrawer.ts
+++ b/web/src/elements/notifications/APIDrawer.ts
@@ -39,7 +39,7 @@ export class APIMiddleware implements Middleware {
}
export const MAX_REQUESTS = 50;
-export const MIDDLEWARE = new APIMiddleware();
+export const API_DRAWER_MIDDLEWARE = new APIMiddleware();
@customElement("ak-api-drawer")
export class APIDrawer extends LitElement {
@@ -76,7 +76,7 @@ export class APIDrawer extends LitElement {
- ${MIDDLEWARE.requests.map(n => this.renderItem(n))}
+ ${API_DRAWER_MIDDLEWARE.requests.map(n => this.renderItem(n))}
diff --git a/web/src/flow.ts b/web/src/flow.ts
deleted file mode 100644
index 9fe22476c..000000000
--- a/web/src/flow.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import "construct-style-sheets-polyfill";
-
-import "./elements/messages/MessageContainer";
-import "./flows/FlowExecutor";
diff --git a/web/src/flows/FlowExecutor.ts b/web/src/flows/FlowExecutor.ts
index f8e63a72f..10297e2b4 100644
--- a/web/src/flows/FlowExecutor.ts
+++ b/web/src/flows/FlowExecutor.ts
@@ -9,6 +9,7 @@ import PFList from "@patternfly/patternfly/components/List/list.css";
import AKGlobal from "../authentik.css";
import { unsafeHTML } from "lit-html/directives/unsafe-html";
+import "./access_denied/FlowAccessDenied";
import "./stages/authenticator_static/AuthenticatorStaticStage";
import "./stages/authenticator_totp/AuthenticatorTOTPStage";
import "./stages/authenticator_validate/AuthenticatorValidateStage";
@@ -16,11 +17,11 @@ import "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
import "./stages/autosubmit/AutosubmitStage";
import "./stages/captcha/CaptchaStage";
import "./stages/consent/ConsentStage";
+import "./stages/dummy/DummyStage";
import "./stages/email/EmailStage";
import "./stages/identification/IdentificationStage";
import "./stages/password/PasswordStage";
import "./stages/prompt/PromptStage";
-import "./access_denied/FlowAccessDenied";
import { ShellChallenge, RedirectChallenge } from "../api/Flows";
import { IdentificationChallenge } from "./stages/identification/IdentificationStage";
import { PasswordChallenge } from "./stages/password/PasswordStage";
@@ -193,6 +194,8 @@ export class FlowExecutor extends LitElement implements StageHost {
return html`
`;
case "ak-stage-consent":
return html`
`;
+ case "ak-stage-dummy":
+ return html`
`;
case "ak-stage-email":
return html`
`;
case "ak-stage-autosubmit":
diff --git a/web/src/flows/access_denied/FlowAccessDenied.ts b/web/src/flows/access_denied/FlowAccessDenied.ts
index e6fe27c79..bdbd3df16 100644
--- a/web/src/flows/access_denied/FlowAccessDenied.ts
+++ b/web/src/flows/access_denied/FlowAccessDenied.ts
@@ -14,7 +14,6 @@ import "../../elements/EmptyState";
export interface AccessDeniedChallenge extends Challenge {
error_message?: string;
- policy_result?: Record
;
}
@customElement("ak-stage-access-denied")
@@ -49,27 +48,6 @@ export class FlowAccessDenied extends BaseStage {
${this.challenge?.error_message &&
html`
${this.challenge.error_message}
`}
- ${this.challenge.policy_result &&
- html`
-
- ${gettext("Explanation:")}
-
-
- {% for source_result in policy_result.source_results %}
-
- {% blocktrans with name=source_result.source_policy.name result=source_result.passing %}
- Policy '{{ name }}' returned result '{{ result }}'
- {% endblocktrans %}
- {% if source_result.messages %}
-
- {% for message in source_result.messages %}
- {{ message }}
- {% endfor %}
-
- {% endif %}
-
- {% endfor %}
- `}
diff --git a/web/src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts b/web/src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
index e79237d7d..cee973c07 100644
--- a/web/src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
+++ b/web/src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
@@ -12,6 +12,7 @@ import { BaseStage } from "../base";
import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState";
import "../../FormStatic";
+import { FlowURLManager } from "../../../api/legacy";
export const STATIC_TOKEN_STYLE = css`
/* Static OTP Tokens */
@@ -61,7 +62,7 @@ export class AuthenticatorStaticStage extends BaseStage {
userAvatar="${this.challenge.pending_user_avatar}"
user=${this.challenge.pending_user}>
@@ -60,7 +62,7 @@ export class AuthenticatorTOTPStage extends BaseStage {
if (!this.challenge?.config_url) return;
navigator.clipboard.writeText(this.challenge?.config_url).then(() => {
showMessage({
- level_tag: "success",
+ level: MessageLevel.success,
message: gettext("Successfully copied TOTP Config.")
});
});
diff --git a/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts b/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
index 21c49bbf2..e048cf178 100644
--- a/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
+++ b/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
@@ -11,6 +11,7 @@ import AKGlobal from "../../../authentik.css";
import { BaseStage, StageHost } from "../base";
import "./AuthenticatorValidateStageWebAuthn";
import "./AuthenticatorValidateStageCode";
+import { PasswordManagerPrefill } from "../identification/IdentificationStage";
export enum DeviceClasses {
STATIC = "static",
@@ -83,6 +84,17 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
${gettext("Use a security key to prove your identity.")}
`;
case DeviceClasses.TOTP:
+ // TOTP is a bit special, assuming that TOTP is allowed from the backend,
+ // and we have a pre-filled value from the password manager,
+ // directly set the the TOTP device Challenge as active.
+ if (PasswordManagerPrefill.totp) {
+ console.debug("authentik/stages/authenticator_validate: found prefill totp code, selecting totp challenge");
+ this.selectedDeviceChallenge = deviceChallenge;
+ // Delay the update as a re-render isn't triggered from here
+ setTimeout(() => {
+ this.requestUpdate();
+ }, 100);
+ }
return html`
${gettext("Traditional authenticator")}
@@ -141,9 +153,9 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
render(): TemplateResult {
if (!this.challenge) {
return html`
- `;
+ ?loading="${true}"
+ header=${gettext("Loading")}>
+ `;
}
// User only has a single device class, so we don't show a picker
if (this.challenge?.device_challenges.length === 1) {
diff --git a/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts b/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
index 0a094ce4f..d5be69405 100644
--- a/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
+++ b/web/src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
@@ -13,6 +13,7 @@ import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState";
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
import "../../FormStatic";
+import { FlowURLManager } from "../../../api/legacy";
@customElement("ak-stage-authenticator-validate-code")
export class AuthenticatorValidateStageWebCode extends BaseStage {
@@ -44,7 +45,7 @@ export class AuthenticatorValidateStageWebCode extends BaseStage {
userAvatar="${this.challenge.pending_user_avatar}"
user=${this.challenge.pending_user}>
diff --git a/web/src/flows/stages/consent/ConsentStage.ts b/web/src/flows/stages/consent/ConsentStage.ts
index 9e0d3a93d..f8c1f1d8e 100644
--- a/web/src/flows/stages/consent/ConsentStage.ts
+++ b/web/src/flows/stages/consent/ConsentStage.ts
@@ -11,6 +11,7 @@ import AKGlobal from "../../../authentik.css";
import { BaseStage } from "../base";
import "../../../elements/EmptyState";
import "../../FormStatic";
+import { FlowURLManager } from "../../../api/legacy";
export interface Permission {
name: string;
@@ -53,7 +54,7 @@ export class ConsentStage extends BaseStage {
userAvatar="${this.challenge.pending_user_avatar}"
user=${this.challenge.pending_user}>
diff --git a/web/src/flows/stages/dummy/DummyStage.ts b/web/src/flows/stages/dummy/DummyStage.ts
new file mode 100644
index 000000000..d54d3389c
--- /dev/null
+++ b/web/src/flows/stages/dummy/DummyStage.ts
@@ -0,0 +1,52 @@
+import { gettext } from "django";
+import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
+import { Challenge } from "../../../api/Flows";
+import PFLogin from "@patternfly/patternfly/components/Login/login.css";
+import PFForm from "@patternfly/patternfly/components/Form/form.css";
+import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
+import PFTitle from "@patternfly/patternfly/components/Title/title.css";
+import PFButton from "@patternfly/patternfly/components/Button/button.css";
+import PFBase from "@patternfly/patternfly/patternfly-base.css";
+import AKGlobal from "../../../authentik.css";
+import { BaseStage } from "../base";
+import "../../../elements/EmptyState";
+import "../../FormStatic";
+
+@customElement("ak-stage-dummy")
+export class DummyStage extends BaseStage {
+
+ @property({ attribute: false })
+ challenge?: Challenge;
+
+ static get styles(): CSSResult[] {
+ return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];
+ }
+
+ render(): TemplateResult {
+ if (!this.challenge) {
+ return html`
+ `;
+ }
+ return html`
+
+ ${this.challenge.title}
+
+
+
+
`;
+ }
+
+}
diff --git a/web/src/flows/stages/password/PasswordStage.ts b/web/src/flows/stages/password/PasswordStage.ts
index 868e84193..0cab171e8 100644
--- a/web/src/flows/stages/password/PasswordStage.ts
+++ b/web/src/flows/stages/password/PasswordStage.ts
@@ -13,6 +13,7 @@ import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState";
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
import "../../FormStatic";
+import { FlowURLManager } from "../../../api/legacy";
export interface PasswordChallenge extends WithUserInfoChallenge {
recovery_url?: string;
@@ -47,7 +48,7 @@ export class PasswordStage extends BaseStage {
userAvatar="${this.challenge.pending_user_avatar}"
user=${this.challenge.pending_user}>
diff --git a/web/src/interfaces/AdminInterface.ts b/web/src/interfaces/AdminInterface.ts
index a31b5b48a..0418c459e 100644
--- a/web/src/interfaces/AdminInterface.ts
+++ b/web/src/interfaces/AdminInterface.ts
@@ -1,3 +1,9 @@
+import "construct-style-sheets-polyfill";
+
+// Elements that are used by SiteShell pages
+// And can't dynamically be imported
+import "../elements/CodeMirror";
+import "../elements/messages/MessageContainer";
import { customElement } from "lit-element";
import { me } from "../api/Users";
import { SidebarItem } from "../elements/sidebar/Sidebar";
diff --git a/web/src/interfaces/FlowInterface.ts b/web/src/interfaces/FlowInterface.ts
new file mode 100644
index 000000000..9ba725a8c
--- /dev/null
+++ b/web/src/interfaces/FlowInterface.ts
@@ -0,0 +1,4 @@
+import "construct-style-sheets-polyfill";
+
+import "../elements/messages/MessageContainer";
+import "../flows/FlowExecutor";
diff --git a/web/src/interfaces/admin/index.html b/web/src/interfaces/admin/index.html
index 793861dac..dcaad682b 100644
--- a/web/src/interfaces/admin/index.html
+++ b/web/src/interfaces/admin/index.html
@@ -8,7 +8,8 @@
-
+
+
authentik
diff --git a/web/src/interfaces/flow/index.html b/web/src/interfaces/flow/index.html
index 9d3071349..ceec0869c 100644
--- a/web/src/interfaces/flow/index.html
+++ b/web/src/interfaces/flow/index.html
@@ -8,7 +8,8 @@
-
+
+
authentik
diff --git a/web/src/main.ts b/web/src/main.ts
deleted file mode 100644
index 12997f4e3..000000000
--- a/web/src/main.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import "construct-style-sheets-polyfill";
-
-// Elements that are used by SiteShell pages
-// And can't dynamically be imported
-import "./elements/buttons/ActionButton";
-import "./elements/buttons/Dropdown";
-import "./elements/buttons/ModalButton";
-import "./elements/buttons/SpinnerButton";
-import "./elements/CodeMirror";
-
-import "./pages/generic/SiteShell";
-import "./interfaces/AdminInterface";
-import "./elements/messages/MessageContainer";
diff --git a/web/src/pages/flows/FlowListPage.ts b/web/src/pages/flows/FlowListPage.ts
index 84c7d9d76..1dc88d311 100644
--- a/web/src/pages/flows/FlowListPage.ts
+++ b/web/src/pages/flows/FlowListPage.ts
@@ -57,8 +57,8 @@ export class FlowListPage extends TablePage
{
`,
html`${item.name}`,
html`${item.designation}`,
- html`${item.stages?.size}`,
- html`${item.policies?.size}`,
+ html`${Array.from(item.stages || []).length}`,
+ html`${Array.from(item.policies || []).length}`,
html`
diff --git a/web/src/pages/generic/SiteShell.ts b/web/src/pages/generic/SiteShell.ts
index 5d87c83a9..1ec767f7e 100644
--- a/web/src/pages/generic/SiteShell.ts
+++ b/web/src/pages/generic/SiteShell.ts
@@ -19,6 +19,7 @@ import AKGlobal from "../../authentik.css";
import CodeMirrorStyle from "codemirror/lib/codemirror.css";
import CodeMirrorTheme from "codemirror/theme/monokai.css";
import { EVENT_REFRESH } from "../../constants";
+import { MessageLevel } from "../../elements/messages/Message";
@customElement("ak-site-shell")
export class SiteShell extends LitElement {
@@ -79,7 +80,7 @@ export class SiteShell extends LitElement {
}
console.debug(`authentik/site-shell: Request failed ${this._url}`);
showMessage({
- level_tag: "error",
+ level: MessageLevel.error,
message: gettext(`Request failed: ${response.statusText}`),
});
this.loading = false;
@@ -148,7 +149,7 @@ export class SiteShell extends LitElement {
})
.catch((e) => {
showMessage({
- level_tag: "error",
+ level: MessageLevel.error,
message: "Unexpected error"
});
console.error(e);
diff --git a/web/src/pages/users/UserActiveForm.ts b/web/src/pages/users/UserActiveForm.ts
index ed7aa7b4d..ed1868521 100644
--- a/web/src/pages/users/UserActiveForm.ts
+++ b/web/src/pages/users/UserActiveForm.ts
@@ -1,6 +1,7 @@
import { gettext } from "django";
import { customElement, html, TemplateResult } from "lit-element";
import { DeleteForm } from "../../elements/forms/DeleteForm";
+import { MessageLevel } from "../../elements/messages/Message";
import { showMessage } from "../../elements/messages/MessageContainer";
@customElement("ak-user-active-form")
@@ -9,14 +10,14 @@ export class UserActiveForm extends DeleteForm {
onSuccess(): void {
showMessage({
message: gettext(`Successfully updated ${this.objectLabel} ${this.obj?.name}`),
- level_tag: "success",
+ level: MessageLevel.success,
});
}
onError(e: Error): void {
showMessage({
message: gettext(`Failed to update ${this.objectLabel}: ${e.toString()}`),
- level_tag: "error",
+ level: MessageLevel.error,
});
}