This commit abstracts access to the object rootInterface()?.tenant? into a single accessor,

`tenant`, that can be mixed into any AKElement object that requires access to it.

Like `WithCapabilitiesConfig` and `WithAuthentikConfig`, this one is named `WithTenantConfig`.

TODO:

``` javascript
rootInterface()?.uiConfig;
me();
```
This commit is contained in:
Ken Sternberg 2023-11-29 15:30:42 -08:00
parent 6228931305
commit 115e2f3dcb
13 changed files with 93 additions and 42 deletions

View file

@ -6,7 +6,7 @@ import "@goauthentik/components/ak-number-input";
import "@goauthentik/components/ak-radio-input"; import "@goauthentik/components/ak-radio-input";
import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-switch-input";
import "@goauthentik/components/ak-text-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/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
@ -31,7 +31,7 @@ import {
} from "./LDAPOptionsAndHelp"; } from "./LDAPOptionsAndHelp";
@customElement("ak-application-wizard-authentication-by-ldap") @customElement("ak-application-wizard-authentication-by-ldap")
export class ApplicationWizardApplicationDetails extends BaseProviderPanel { export class ApplicationWizardApplicationDetails extends WithTenantConfig(BaseProviderPanel, true) {
render() { render() {
const provider = this.wizard.provider as LDAPProvider | undefined; const provider = this.wizard.provider as LDAPProvider | undefined;
@ -52,7 +52,7 @@ export class ApplicationWizardApplicationDetails extends BaseProviderPanel {
<ak-tenanted-flow-search <ak-tenanted-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authentication} flowType=${FlowsInstancesListDesignationEnum.Authentication}
.currentFlow=${provider?.authorizationFlow} .currentFlow=${provider?.authorizationFlow}
.tenantFlow=${rootInterface()?.tenant?.flowAuthentication} .tenantFlow=${this.tenant.flowAuthentication}
required required
></ak-tenanted-flow-search> ></ak-tenanted-flow-search>
<p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p> <p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p>

View file

@ -2,7 +2,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search"; import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search";
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-text-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/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
@ -16,7 +16,10 @@ import { FlowsInstancesListDesignationEnum, RadiusProvider } from "@goauthentik/
import BaseProviderPanel from "../BaseProviderPanel"; import BaseProviderPanel from "../BaseProviderPanel";
@customElement("ak-application-wizard-authentication-by-radius") @customElement("ak-application-wizard-authentication-by-radius")
export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel { export class ApplicationWizardAuthenticationByRadius extends WithTenantConfig(
BaseProviderPanel,
true,
) {
render() { render() {
const provider = this.wizard.provider as RadiusProvider | undefined; const provider = this.wizard.provider as RadiusProvider | undefined;
@ -37,7 +40,7 @@ export class ApplicationWizardAuthenticationByRadius extends BaseProviderPanel {
<ak-tenanted-flow-search <ak-tenanted-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authentication} flowType=${FlowsInstancesListDesignationEnum.Authentication}
.currentFlow=${provider?.authorizationFlow} .currentFlow=${provider?.authorizationFlow}
.tenantFlow=${rootInterface()?.tenant?.flowAuthentication} .tenantFlow=${this.tenant.flowAuthentication}
required required
></ak-tenanted-flow-search> ></ak-tenanted-flow-search>
<p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p> <p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p>

View file

@ -9,11 +9,11 @@ import { MessageLevel } from "@goauthentik/common/messages";
import { uiConfig } from "@goauthentik/common/ui/config"; import { uiConfig } from "@goauthentik/common/ui/config";
import { first } from "@goauthentik/common/utils"; import { first } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-status-label"; import "@goauthentik/components/ak-status-label";
import { rootInterface } from "@goauthentik/elements/Base";
import { import {
CapabilitiesEnum, CapabilitiesEnum,
WithCapabilitiesConfig, WithCapabilitiesConfig,
} from "@goauthentik/elements/Interface/capabilitiesProvider"; } from "@goauthentik/elements/Interface/capabilitiesProvider";
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/Dropdown"; import "@goauthentik/elements/buttons/Dropdown";
import "@goauthentik/elements/forms/DeleteBulkForm"; import "@goauthentik/elements/forms/DeleteBulkForm";
@ -110,7 +110,10 @@ export class RelatedUserAdd extends Form<{ users: number[] }> {
} }
@customElement("ak-user-related-list") @customElement("ak-user-related-list")
export class RelatedUserList extends WithCapabilitiesConfig(Table<User>) { export class RelatedUserList extends WithTenantConfig(
WithCapabilitiesConfig(Table<User>, true),
true,
) {
expandable = true; expandable = true;
checkbox = true; checkbox = true;
@ -295,7 +298,7 @@ export class RelatedUserList extends WithCapabilitiesConfig(Table<User>) {
${msg("Set password")} ${msg("Set password")}
</button> </button>
</ak-forms-modal> </ak-forms-modal>
${rootInterface()?.tenant?.flowRecovery ${this.tenant?.flowRecovery
? html` ? html`
<ak-action-button <ak-action-button
class="pf-m-secondary" class="pf-m-secondary"

View file

@ -2,7 +2,7 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search"; import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils"; import { first } 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/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
@ -25,7 +25,7 @@ import {
} from "@goauthentik/api"; } from "@goauthentik/api";
@customElement("ak-provider-ldap-form") @customElement("ak-provider-ldap-form")
export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> { export class LDAPProviderFormPage extends WithTenantConfig(ModelForm<LDAPProvider, number>, true) {
async loadInstance(pk: number): Promise<LDAPProvider> { async loadInstance(pk: number): Promise<LDAPProvider> {
return new ProvidersApi(DEFAULT_CONFIG).providersLdapRetrieve({ return new ProvidersApi(DEFAULT_CONFIG).providersLdapRetrieve({
id: pk, id: pk,
@ -76,7 +76,7 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
<ak-tenanted-flow-search <ak-tenanted-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authentication} flowType=${FlowsInstancesListDesignationEnum.Authentication}
.currentFlow=${this.instance?.authorizationFlow} .currentFlow=${this.instance?.authorizationFlow}
.tenantFlow=${rootInterface()?.tenant?.flowAuthentication} .tenantFlow=${this.tenant?.flowAuthentication}
required required
></ak-tenanted-flow-search> ></ak-tenanted-flow-search>
<p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p> <p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p>

View file

@ -1,6 +1,6 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; 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/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
@ -14,7 +14,10 @@ import { customElement } from "lit/decorators.js";
import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api"; import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api";
@customElement("ak-provider-radius-form") @customElement("ak-provider-radius-form")
export class RadiusProviderFormPage extends ModelForm<RadiusProvider, number> { export class RadiusProviderFormPage extends WithTenantConfig(
ModelForm<RadiusProvider, number>,
true,
) {
loadInstance(pk: number): Promise<RadiusProvider> { loadInstance(pk: number): Promise<RadiusProvider> {
return new ProvidersApi(DEFAULT_CONFIG).providersRadiusRetrieve({ return new ProvidersApi(DEFAULT_CONFIG).providersRadiusRetrieve({
id: pk, id: pk,
@ -65,7 +68,7 @@ export class RadiusProviderFormPage extends ModelForm<RadiusProvider, number> {
<ak-tenanted-flow-search <ak-tenanted-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authentication} flowType=${FlowsInstancesListDesignationEnum.Authentication}
.currentFlow=${this.instance?.authorizationFlow} .currentFlow=${this.instance?.authorizationFlow}
.tenantFlow=${rootInterface()?.tenant?.flowAuthentication} .tenantFlow=${this.tenant?.flowAuthentication}
required required
></ak-tenanted-flow-search> ></ak-tenanted-flow-search>
<p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p> <p class="pf-c-form__helper-text">${msg("Flow used for users to authenticate.")}</p>

View file

@ -16,6 +16,7 @@ import {
CapabilitiesEnum, CapabilitiesEnum,
WithCapabilitiesConfig, WithCapabilitiesConfig,
} from "@goauthentik/elements/Interface/capabilitiesProvider"; } from "@goauthentik/elements/Interface/capabilitiesProvider";
import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
import { PFSize } from "@goauthentik/elements/Spinner"; import { PFSize } from "@goauthentik/elements/Spinner";
import "@goauthentik/elements/TreeView"; import "@goauthentik/elements/TreeView";
import "@goauthentik/elements/buttons/ActionButton"; import "@goauthentik/elements/buttons/ActionButton";
@ -90,7 +91,10 @@ const recoveryButtonStyles = css`
`; `;
@customElement("ak-user-list") @customElement("ak-user-list")
export class UserListPage extends WithCapabilitiesConfig(TablePage<User>) { export class UserListPage extends WithTenantConfig(
WithCapabilitiesConfig(TablePage<User>, true),
true,
) {
expandable = true; expandable = true;
checkbox = true; checkbox = true;
@ -351,7 +355,7 @@ export class UserListPage extends WithCapabilitiesConfig(TablePage<User>) {
${msg("Set password")} ${msg("Set password")}
</button> </button>
</ak-forms-modal> </ak-forms-modal>
${rootInterface()?.tenant?.flowRecovery ${this.tenant.flowRecovery
? html` ? html`
<ak-action-button <ak-action-button
class="pf-m-secondary" class="pf-m-secondary"

View file

@ -1,7 +1,11 @@
import { createContext } from "@lit-labs/context"; import { createContext } from "@lit-labs/context";
import { type Config } from "@goauthentik/api"; import type { Config, CurrentTenant } from "@goauthentik/api";
export const authentikConfigContext = createContext<Config>(Symbol("authentik-config-context")); export const authentikConfigContext = createContext<Config>(Symbol("authentik-config-context"));
export const authentikTenantContext = createContext<CurrentTenant>(
Symbol("authentik-tenant-context"),
);
export default authentikConfigContext; export default authentikConfigContext;

View file

@ -1,6 +1,9 @@
import { config, tenant } from "@goauthentik/common/api/config"; import { config, tenant } from "@goauthentik/common/api/config";
import { UIConfig, uiConfig } from "@goauthentik/common/ui/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 type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types";
import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet";
@ -21,9 +24,6 @@ type AkInterface = HTMLElement & {
}; };
export class Interface extends AKElement implements AkInterface { export class Interface extends AKElement implements AkInterface {
@state()
tenant?: CurrentTenant;
@state() @state()
uiConfig?: UIConfig; uiConfig?: UIConfig;
@ -45,6 +45,24 @@ export class Interface extends AKElement implements AkInterface {
return this._config; 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() { constructor() {
super(); super();
document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)]; document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)];

View file

@ -12,7 +12,7 @@ export function WithAuthentikConfig<T extends Constructor<LitElement>>(
superclass: T, superclass: T,
subscribe = false, subscribe = false,
) { ) {
class WithAkConfigProvider extends superclass { abstract class WithAkConfigProvider extends superclass {
@consume({ context: authentikConfigContext, subscribe }) @consume({ context: authentikConfigContext, subscribe })
public authentikConfig!: Config; public authentikConfig!: Config;
} }

View file

@ -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<T = object> = abstract new (...args: any[]) => T;
export function WithTenantConfig<T extends Constructor<LitElement>>(
superclass: T,
subscribe = false,
) {
abstract class WithTenantProvider extends superclass {
@consume({ context: authentikTenantContext, subscribe })
public tenant!: CurrentTenant;
}
return WithTenantProvider;
}

View file

@ -8,7 +8,8 @@ import {
} from "@goauthentik/common/constants"; } from "@goauthentik/common/constants";
import { currentInterface } from "@goauthentik/common/sentry"; import { currentInterface } from "@goauthentik/common/sentry";
import { me } from "@goauthentik/common/users"; 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 "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
@ -23,7 +24,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { EventsApi } from "@goauthentik/api"; import { EventsApi } from "@goauthentik/api";
@customElement("ak-page-header") @customElement("ak-page-header")
export class PageHeader extends AKElement { export class PageHeader extends WithTenantConfig(AKElement, true) {
@property() @property()
icon?: string; icon?: string;
@ -35,9 +36,8 @@ export class PageHeader extends AKElement {
@property() @property()
set header(value: string) { set header(value: string) {
const tenant = rootInterface()?.tenant;
const currentIf = currentInterface(); const currentIf = currentInterface();
let title = tenant?.brandingTitle || TITLE_DEFAULT; let title = this.tenant?.brandingTitle || TITLE_DEFAULT;
if (currentIf === "admin") { if (currentIf === "admin") {
title = `${msg("Admin")} - ${title}`; title = `${msg("Admin")} - ${title}`;
} }

View file

@ -1,6 +1,6 @@
import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants"; import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants";
import { first } from "@goauthentik/common/utils"; import { AKElement } from "@goauthentik/elements/Base";
import { AKElement, rootInterface } from "@goauthentik/elements/Base"; import { WithTenantConfig } from "@goauthentik/elements/Interface/tenantProvider";
import { CSSResult, TemplateResult, css, html } from "lit"; import { CSSResult, TemplateResult, css, html } from "lit";
import { customElement } from "lit/decorators.js"; import { customElement } from "lit/decorators.js";
@ -27,7 +27,7 @@ export const DefaultTenant: CurrentTenant = {
}; };
@customElement("ak-sidebar-brand") @customElement("ak-sidebar-brand")
export class SidebarBrand extends AKElement { export class SidebarBrand extends WithTenantConfig(AKElement, true) {
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [ return [
PFBase, PFBase,
@ -85,10 +85,7 @@ export class SidebarBrand extends AKElement {
<a href="#/" class="pf-c-page__header-brand-link"> <a href="#/" class="pf-c-page__header-brand-link">
<div class="pf-c-brand ak-brand"> <div class="pf-c-brand ak-brand">
<img <img
src="${first( src=${this.tenant?.brandingLogo ?? DefaultTenant.brandingLogo}
rootInterface()?.tenant?.brandingLogo,
DefaultTenant.brandingLogo,
)}"
alt="authentik Logo" alt="authentik Logo"
loading="lazy" loading="lazy"
/> />

View file

@ -2,14 +2,15 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants"; import { EVENT_REFRESH } from "@goauthentik/common/constants";
import { MessageLevel } from "@goauthentik/common/messages"; import { MessageLevel } from "@goauthentik/common/messages";
import { refreshMe } from "@goauthentik/common/users"; 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 { showMessage } from "@goauthentik/elements/messages/MessageContainer";
import { StageHost } from "@goauthentik/flow/stages/base"; import { StageHost } from "@goauthentik/flow/stages/base";
import "@goauthentik/user/user-settings/details/stages/prompt/PromptStage"; import "@goauthentik/user/user-settings/details/stages/prompt/PromptStage";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; 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 { unsafeHTML } from "lit/directives/unsafe-html.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
@ -21,7 +22,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { import {
ChallengeChoices, ChallengeChoices,
ChallengeTypes, ChallengeTypes,
CurrentTenant,
FlowChallengeResponseRequest, FlowChallengeResponseRequest,
FlowErrorChallenge, FlowErrorChallenge,
FlowsApi, FlowsApi,
@ -31,13 +31,13 @@ import {
} from "@goauthentik/api"; } from "@goauthentik/api";
@customElement("ak-user-settings-flow-executor") @customElement("ak-user-settings-flow-executor")
export class UserSettingsFlowExecutor extends AKElement implements StageHost { export class UserSettingsFlowExecutor
extends WithTenantConfig(AKElement, true)
implements StageHost
{
@property() @property()
flowSlug?: string; flowSlug?: string;
@state()
tenant?: CurrentTenant;
private _challenge?: ChallengeTypes; private _challenge?: ChallengeTypes;
@property({ attribute: false }) @property({ attribute: false })
@ -87,7 +87,6 @@ export class UserSettingsFlowExecutor extends AKElement implements StageHost {
} }
firstUpdated(): void { firstUpdated(): void {
this.tenant = rootInterface()?.tenant;
this.flowSlug = this.tenant?.flowUserSettings; this.flowSlug = this.tenant?.flowUserSettings;
if (!this.flowSlug) { if (!this.flowSlug) {
return; return;