diff --git a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts index 2349af45b..8858f5bf4 100644 --- a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts +++ b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts @@ -6,7 +6,7 @@ import "@goauthentik/components/ak-number-input"; import "@goauthentik/components/ak-radio-input"; import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-text-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -31,7 +31,7 @@ import { } from "./LDAPOptionsAndHelp"; @customElement("ak-application-wizard-authentication-by-ldap") -export class ApplicationWizardApplicationDetails extends BaseProviderPanel { +export class ApplicationWizardApplicationDetails extends WithTenantConfig(BaseProviderPanel, true) { render() { const provider = this.wizard.provider as LDAPProvider | undefined; @@ -52,7 +52,7 @@ export class ApplicationWizardApplicationDetails extends BaseProviderPanel {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts b/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts index d107eab0f..ab4260df0 100644 --- a/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts +++ b/web/src/admin/applications/wizard/methods/radius/ak-application-wizard-authentication-by-radius.ts @@ -2,7 +2,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search"; import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-text-input"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -16,7 +16,10 @@ import { FlowsInstancesListDesignationEnum, RadiusProvider } from "@goauthentik/ import BaseProviderPanel from "../BaseProviderPanel"; @customElement("ak-application-wizard-authentication-by-radius") -export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel { +export class ApplicationWizardAuthenticationByRadius extends WithTenantConfig( + BaseProviderPanel, + true, +) { render() { const provider = this.wizard.provider as RadiusProvider | undefined; @@ -37,7 +40,7 @@ export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/groups/RelatedUserList.ts b/web/src/admin/groups/RelatedUserList.ts index 27450fb82..5a1f0ebd8 100644 --- a/web/src/admin/groups/RelatedUserList.ts +++ b/web/src/admin/groups/RelatedUserList.ts @@ -9,11 +9,11 @@ import { MessageLevel } from "@goauthentik/common/messages"; import { uiConfig } from "@goauthentik/common/ui/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-status-label"; -import { rootInterface } from "@goauthentik/elements/Base"; import { CapabilitiesEnum, WithCapabilitiesConfig, } from "@goauthentik/elements/Interface/capabilitiesProvider"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/Dropdown"; import "@goauthentik/elements/forms/DeleteBulkForm"; @@ -110,7 +110,10 @@ export class RelatedUserAdd extends Form<{ users: number[] }> { } @customElement("ak-user-related-list") -export class RelatedUserList extends WithCapabilitiesConfig(Table) { +export class RelatedUserList extends WithTenantConfig( + WithCapabilitiesConfig(Table, true), + true, +) { expandable = true; checkbox = true; @@ -295,7 +298,7 @@ export class RelatedUserList extends WithCapabilitiesConfig(Table) { ${msg("Set password")} - ${rootInterface()?.tenant?.flowRecovery + ${this.tenant?.flowRecovery ? html` { +export class LDAPProviderFormPage extends WithTenantConfig(ModelForm, true) { async loadInstance(pk: number): Promise { return new ProvidersApi(DEFAULT_CONFIG).providersLdapRetrieve({ id: pk, @@ -76,7 +76,7 @@ export class LDAPProviderFormPage extends ModelForm {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/providers/radius/RadiusProviderForm.ts b/web/src/admin/providers/radius/RadiusProviderForm.ts index 3898ba048..fda74ef46 100644 --- a/web/src/admin/providers/radius/RadiusProviderForm.ts +++ b/web/src/admin/providers/radius/RadiusProviderForm.ts @@ -1,6 +1,6 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; -import { rootInterface } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; @@ -14,7 +14,10 @@ import { customElement } from "lit/decorators.js"; import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api"; @customElement("ak-provider-radius-form") -export class RadiusProviderFormPage extends ModelForm { +export class RadiusProviderFormPage extends WithTenantConfig( + ModelForm, + true, +) { loadInstance(pk: number): Promise { return new ProvidersApi(DEFAULT_CONFIG).providersRadiusRetrieve({ id: pk, @@ -65,7 +68,7 @@ export class RadiusProviderFormPage extends ModelForm {

${msg("Flow used for users to authenticate.")}

diff --git a/web/src/admin/users/UserListPage.ts b/web/src/admin/users/UserListPage.ts index e9d0c6f09..e90228722 100644 --- a/web/src/admin/users/UserListPage.ts +++ b/web/src/admin/users/UserListPage.ts @@ -16,6 +16,7 @@ import { CapabilitiesEnum, WithCapabilitiesConfig, } from "@goauthentik/elements/Interface/capabilitiesProvider"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { PFSize } from "@goauthentik/elements/Spinner"; import "@goauthentik/elements/TreeView"; import "@goauthentik/elements/buttons/ActionButton"; @@ -90,7 +91,10 @@ const recoveryButtonStyles = css` `; @customElement("ak-user-list") -export class UserListPage extends WithCapabilitiesConfig(TablePage) { +export class UserListPage extends WithTenantConfig( + WithCapabilitiesConfig(TablePage, true), + true, +) { expandable = true; checkbox = true; @@ -351,7 +355,7 @@ export class UserListPage extends WithCapabilitiesConfig(TablePage) { ${msg("Set password")} - ${rootInterface()?.tenant?.flowRecovery + ${this.tenant.flowRecovery ? html` (Symbol("authentik-config-context")); +export const authentikTenantContext = createContext( + Symbol("authentik-tenant-context"), +); + export default authentikConfigContext; diff --git a/web/src/elements/Interface/Interface.ts b/web/src/elements/Interface/Interface.ts index 744a16095..b2470cfd2 100644 --- a/web/src/elements/Interface/Interface.ts +++ b/web/src/elements/Interface/Interface.ts @@ -1,6 +1,9 @@ import { config, tenant } from "@goauthentik/common/api/config"; import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; -import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; +import { + authentikConfigContext, + authentikTenantContext, +} from "@goauthentik/elements/AuthentikContexts"; import type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types"; import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; @@ -21,9 +24,6 @@ type AkInterface = HTMLElement & { }; export class Interface extends AKElement implements AkInterface { - @state() - tenant?: CurrentTenant; - @state() uiConfig?: UIConfig; @@ -45,6 +45,24 @@ export class Interface extends AKElement implements AkInterface { return this._config; } + _tenantContext = new ContextProvider(this, { + context: authentikTenantContext, + initialValue: undefined, + }); + + _tenant?: CurrentTenant; + + @state() + set tenant(c: CurrentTenant) { + this._tenant = c; + this._tenantContext.setValue(c); + this.requestUpdate(); + } + + get tenant(): CurrentTenant | undefined { + return this._tenant; + } + constructor() { super(); document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; diff --git a/web/src/elements/Interface/authentikConfigProvider.ts b/web/src/elements/Interface/authentikConfigProvider.ts index 7fba78923..169ec82a0 100644 --- a/web/src/elements/Interface/authentikConfigProvider.ts +++ b/web/src/elements/Interface/authentikConfigProvider.ts @@ -12,7 +12,7 @@ export function WithAuthentikConfig>( superclass: T, subscribe = false, ) { - class WithAkConfigProvider extends superclass { + abstract class WithAkConfigProvider extends superclass { @consume({ context: authentikConfigContext, subscribe }) public authentikConfig!: Config; } diff --git a/web/src/elements/Interface/tenantProvider.ts b/web/src/elements/Interface/tenantProvider.ts new file mode 100644 index 000000000..e1837935c --- /dev/null +++ b/web/src/elements/Interface/tenantProvider.ts @@ -0,0 +1,20 @@ +import { authentikTenantContext } from "@goauthentik/elements/AuthentikContexts"; + +import { consume } from "@lit-labs/context"; +import type { LitElement } from "lit"; + +import type { CurrentTenant } from "@goauthentik/api"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Constructor = abstract new (...args: any[]) => T; + +export function WithTenantConfig>( + superclass: T, + subscribe = false, +) { + abstract class WithTenantProvider extends superclass { + @consume({ context: authentikTenantContext, subscribe }) + public tenant!: CurrentTenant; + } + return WithTenantProvider; +} diff --git a/web/src/elements/PageHeader.ts b/web/src/elements/PageHeader.ts index 3f187291b..ed8219ef9 100644 --- a/web/src/elements/PageHeader.ts +++ b/web/src/elements/PageHeader.ts @@ -8,7 +8,8 @@ import { } from "@goauthentik/common/constants"; import { currentInterface } from "@goauthentik/common/sentry"; import { me } from "@goauthentik/common/users"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg } from "@lit/localize"; @@ -23,7 +24,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { EventsApi } from "@goauthentik/api"; @customElement("ak-page-header") -export class PageHeader extends AKElement { +export class PageHeader extends WithTenantConfig(AKElement, true) { @property() icon?: string; @@ -35,9 +36,8 @@ export class PageHeader extends AKElement { @property() set header(value: string) { - const tenant = rootInterface()?.tenant; const currentIf = currentInterface(); - let title = tenant?.brandingTitle || TITLE_DEFAULT; + let title = this.tenant?.brandingTitle || TITLE_DEFAULT; if (currentIf === "admin") { title = `${msg("Admin")} - ${title}`; } diff --git a/web/src/elements/sidebar/SidebarBrand.ts b/web/src/elements/sidebar/SidebarBrand.ts index fa442b36c..b603c3c75 100644 --- a/web/src/elements/sidebar/SidebarBrand.ts +++ b/web/src/elements/sidebar/SidebarBrand.ts @@ -1,6 +1,6 @@ import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants"; -import { first } from "@goauthentik/common/utils"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { CSSResult, TemplateResult, css, html } from "lit"; import { customElement } from "lit/decorators.js"; @@ -27,7 +27,7 @@ export const DefaultTenant: CurrentTenant = { }; @customElement("ak-sidebar-brand") -export class SidebarBrand extends AKElement { +export class SidebarBrand extends WithTenantConfig(AKElement, true) { static get styles(): CSSResult[] { return [ PFBase, @@ -85,10 +85,7 @@ export class SidebarBrand extends AKElement {
authentik Logo diff --git a/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts b/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts index e7aa36343..f4252f58b 100644 --- a/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts +++ b/web/src/user/user-settings/details/UserSettingsFlowExecutor.ts @@ -2,14 +2,15 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { EVENT_REFRESH } from "@goauthentik/common/constants"; import { MessageLevel } from "@goauthentik/common/messages"; import { refreshMe } from "@goauthentik/common/users"; -import { AKElement, rootInterface } from "@goauthentik/elements/Base"; +import { AKElement } from "@goauthentik/elements/Base"; +import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider"; import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; import { StageHost } from "@goauthentik/flow/stages/base"; import "@goauthentik/user/user-settings/details/stages/prompt/PromptStage"; import { msg } from "@lit/localize"; import { CSSResult, TemplateResult, html } from "lit"; -import { customElement, property, state } from "lit/decorators.js"; +import { customElement, property } from "lit/decorators.js"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; @@ -21,7 +22,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { ChallengeChoices, ChallengeTypes, - CurrentTenant, FlowChallengeResponseRequest, FlowErrorChallenge, FlowsApi, @@ -31,13 +31,13 @@ import { } from "@goauthentik/api"; @customElement("ak-user-settings-flow-executor") -export class UserSettingsFlowExecutor extends AKElement implements StageHost { +export class UserSettingsFlowExecutor + extends WithTenantConfig(AKElement, true) + implements StageHost +{ @property() flowSlug?: string; - @state() - tenant?: CurrentTenant; - private _challenge?: ChallengeTypes; @property({ attribute: false }) @@ -87,7 +87,6 @@ export class UserSettingsFlowExecutor extends AKElement implements StageHost { } firstUpdated(): void { - this.tenant = rootInterface()?.tenant; this.flowSlug = this.tenant?.flowUserSettings; if (!this.flowSlug) { return;