diff --git a/web/src/admin/Routes.ts b/web/src/admin/Routes.ts
index d7f9792c9..f6df48cbb 100644
--- a/web/src/admin/Routes.ts
+++ b/web/src/admin/Routes.ts
@@ -136,9 +136,9 @@ export const ROUTES: Route[] = [
await import("@goauthentik/admin/crypto/CertificateKeyPairListPage");
return html``;
}),
- new Route(new RegExp("^/admin/settings$"), async() => {
- await import("@goauthentik/admin/admin-settings/AdminSettingsViewPage");
- return html``;
+ new Route(new RegExp("^/admin/settings$"), async () => {
+ await import("@goauthentik/admin/admin-settings/AdminSettingsPage");
+ return html``;
}),
new Route(new RegExp("^/blueprints/instances$"), async () => {
await import("@goauthentik/admin/blueprints/BlueprintListPage");
diff --git a/web/src/admin/admin-settings/AdminSettingsForm.ts b/web/src/admin/admin-settings/AdminSettingsForm.ts
index b63964f8e..0a5d55118 100644
--- a/web/src/admin/admin-settings/AdminSettingsForm.ts
+++ b/web/src/admin/admin-settings/AdminSettingsForm.ts
@@ -1,49 +1,156 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { dateTimeLocal, first } from "@goauthentik/common/utils";
+import "@goauthentik/components/ak-switch-input";
+import "@goauthentik/components/ak-text-input";
+import "@goauthentik/components/ak-textarea-input";
+import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
-import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
-import { customElement, state } from "lit/decorators.js";
+import { customElement, property, state } from "lit/decorators.js";
-import { AdminApi, Settings } from "@goauthentik/api";
+import PFList from "@patternfly/patternfly/components/List/list.css";
+
+import { AdminApi, Settings, SettingsRequest } from "@goauthentik/api";
@customElement("ak-admin-settings-form")
-export class AdminSettingsForm extends ModelForm {
-
- async loadInstance(pk: string): Promise {
- return await new AdminApi(DEFAULT_CONFIG).adminSettingsRetrieve();
+export class AdminSettingsForm extends Form {
+ @property({ attribute: false })
+ set settings(value: Settings) {
+ this._settings = value;
}
+ private _settings?: Settings;
+
getSuccessMessage(): string {
return msg("Successfully updated settings.");
}
- async send(data: Settings): Promise {
+ async send(data: SettingsRequest): Promise {
return new AdminApi(DEFAULT_CONFIG).adminSettingsUpdate({
- settingsRequest: data
+ settingsRequest: data,
});
}
+ static get styles(): CSSResult[] {
+ return super.styles.concat(PFList);
+ }
+
renderForm(): TemplateResult {
- return html`
+ ${msg(
+ "Configure how authentik should show avatars for users. The following values can be set:",
+ )}
+
+
+
+
none: ${msg(
+ "Disables per-user avatars and just shows a 1x1 pixel transparent picture",
+ )}
+
gravatar: ${msg(
+ "Uses gravatar with the user's email address",
+ )}
+
initials: ${msg(
+ "Generated avatars based on the user's name",
+ )}
+
${msg(
+ "Any URL: If you want to use images hosted on another server, you can set any URL. Additionally, these placeholders can be used:",
+ )}
+
+
%(username)s: ${msg(
+ "The user's username",
+ )}
+
%(mail_hash)s: ${msg(
+ "The email address, md5 hashed",
+ )}
+
%(upn)s: ${msg(
+ "The user's UPN, if set (otherwise an empty string)",
+ )}
+
+
+
${msg(
+ html`An attribute path like
+ attributes.something.avatar, which can be used in
+ combination with the file field to allow users to upload custom
+ avatars for themselves.`,
+ )}
+
+
+
+ ${msg(
+ "Multiple values can be set, comma-separated, and authentik will fallback to the next mode when no avatar could be found.",
+ )}
+ ${msg(
+ html`For example, setting this to gravatar,initials will
+ attempt to get an avatar from Gravatar, and if the user has not
+ configured on there, it will fallback to a generated avatar.`,
+ )}
+
+ `}
+ required
>
-
-
- ${msg("Configure how authentik should show avatars for users.")}
-
- `;
+
+
+
+
+
+
+
+
+
+
+
+
+ ${msg(
+ "This option configures the footer links on the flow executor pages. It must be a valid JSON list and can be used as follows:",
+ )}
+ [{"name": "Link Name","href":"https://goauthentik.io"}]
+
+ `}
+ >
+
+ `;
}
}
diff --git a/web/src/admin/admin-settings/AdminSettingsPage.ts b/web/src/admin/admin-settings/AdminSettingsPage.ts
new file mode 100644
index 000000000..680b72a0f
--- /dev/null
+++ b/web/src/admin/admin-settings/AdminSettingsPage.ts
@@ -0,0 +1,110 @@
+import "@goauthentik/admin/admin-settings/AdminSettingsForm";
+import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
+import { EVENT_REFRESH } from "@goauthentik/common/constants";
+import { convertToTitle } from "@goauthentik/common/utils";
+import "@goauthentik/components/events/ObjectChangelog";
+import { AKElement } from "@goauthentik/elements/Base";
+import "@goauthentik/elements/CodeMirror";
+import "@goauthentik/elements/EmptyState";
+import "@goauthentik/elements/Markdown";
+import "@goauthentik/elements/PageHeader";
+import "@goauthentik/elements/Tabs";
+import "@goauthentik/elements/buttons/ModalButton";
+import "@goauthentik/elements/buttons/SpinnerButton";
+import "@goauthentik/elements/buttons/SpinnerButton";
+import "@goauthentik/elements/forms/ModalForm";
+
+import { msg } from "@lit/localize";
+import { CSSResult, TemplateResult, html } from "lit";
+import { customElement, property, state } from "lit/decorators.js";
+
+import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
+import PFButton from "@patternfly/patternfly/components/Button/button.css";
+import PFCard from "@patternfly/patternfly/components/Card/card.css";
+import PFContent from "@patternfly/patternfly/components/Content/content.css";
+import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
+import PFForm from "@patternfly/patternfly/components/Form/form.css";
+import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
+import PFPage from "@patternfly/patternfly/components/Page/page.css";
+import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
+import PFBase from "@patternfly/patternfly/patternfly-base.css";
+
+import { AdminApi, Settings } from "@goauthentik/api";
+
+@customElement("ak-admin-settings")
+export class AdminSettingsPage extends AKElement {
+ static get styles(): CSSResult[] {
+ return [
+ PFBase,
+ PFButton,
+ PFPage,
+ PFGrid,
+ PFContent,
+ PFCard,
+ PFDescriptionList,
+ PFForm,
+ PFFormControl,
+ PFBanner,
+ ];
+ }
+ @property({ attribute: false })
+ settings?: Settings;
+
+ loadSettings(): void {
+ new AdminApi(DEFAULT_CONFIG).adminSettingsRetrieve().then((settings) => {
+ this.settings = settings;
+ });
+ }
+
+ firstUpdated(): void {
+ this.loadSettings();
+ }
+
+ async save(): void {
+ const form = this.shadowRoot?.querySelector("ak-admin-settings-form");
+ if (!form) {
+ return;
+ }
+ await form.submit(new Event("submit"));
+ this.resetForm();
+ }
+
+ resetForm(): void {
+ const form = this.shadowRoot?.querySelector("ak-admin-settings-form");
+ if (!form) {
+ return;
+ }
+ this.loadSettings();
+ form.settings = this.settings;
+ form.resetForm();
+ }
+
+ render(): TemplateResult {
+ if (!this.settings) {
+ return html``;
+ }
+ return html`
+
+ ${msg("System settings")}
+
+
+
+
+ {
+ await this.save();
+ }}
+ class="pf-m-primary"
+ >${msg("Save")}
+ {
+ this.resetForm();
+ }}
+ class="pf-m-secondary"
+ >${msg("Cancel")}
+
+ `;
+ }
+}
diff --git a/web/src/admin/admin-settings/AdminSettingsViewPage.ts b/web/src/admin/admin-settings/AdminSettingsViewPage.ts
deleted file mode 100644
index 2b39d7eeb..000000000
--- a/web/src/admin/admin-settings/AdminSettingsViewPage.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-import "@goauthentik/admin/admin-settings/AdminSettingsForm";
-import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
-import { EVENT_REFRESH } from "@goauthentik/common/constants";
-import { convertToTitle } from "@goauthentik/common/utils";
-import "@goauthentik/components/events/ObjectChangelog";
-import { AKElement } from "@goauthentik/elements/Base";
-import "@goauthentik/elements/CodeMirror";
-import "@goauthentik/elements/EmptyState";
-import "@goauthentik/elements/Markdown";
-import "@goauthentik/elements/PageHeader";
-import "@goauthentik/elements/Tabs";
-import "@goauthentik/elements/buttons/ModalButton";
-import "@goauthentik/elements/buttons/SpinnerButton";
-import "@goauthentik/elements/forms/ModalForm";
-
-import { msg } from "@lit/localize";
-import { CSSResult, TemplateResult, html } from "lit";
-import { customElement, property, state } from "lit/decorators.js";
-
-import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
-import PFButton from "@patternfly/patternfly/components/Button/button.css";
-import PFCard from "@patternfly/patternfly/components/Card/card.css";
-import PFContent from "@patternfly/patternfly/components/Content/content.css";
-import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
-import PFForm from "@patternfly/patternfly/components/Form/form.css";
-import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
-import PFPage from "@patternfly/patternfly/components/Page/page.css";
-import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
-import PFBase from "@patternfly/patternfly/patternfly-base.css";
-
-import { AdminApi, Settings } from "@goauthentik/api";
-
-@customElement("ak-admin-settings-view")
-export class AdminSettingsViewPage extends AKElement {
- @property({ attribute: false })
- settings?: Settings;
-
- firstUpdated(): void {
- new AdminApi(DEFAULT_CONFIG).adminSettingsRetrieve().then((settings) => {
- this.settings = settings;
- });
- }
-
- static get styles(): CSSResult[] {
- return [
- PFBase,
- PFButton,
- PFPage,
- PFGrid,
- PFContent,
- PFCard,
- PFDescriptionList,
- PFForm,
- PFFormControl,
- PFBanner,
- ];
- }
-
- render(): TemplateResult {
- if (!this.settings) {
- return html``;
- }
- // TODO: someone else than Marc, make this look ok, perhaps by directly embedding the form
- // with Save/Cancel buttons
- // TODO: add descriptive text about what each of these do, as is currently presented in
- // https://goauthentik.io/docs/installation/configuration
- return html`
- ${msg("System settings")}
-
-
-