diff --git a/web/src/admin/common/ak-license-notice.ts b/web/src/admin/common/ak-license-notice.ts
new file mode 100644
index 000000000..db8eeca1f
--- /dev/null
+++ b/web/src/admin/common/ak-license-notice.ts
@@ -0,0 +1,24 @@
+import "@goauthentik/elements/Alert";
+import { AKElement } from "@goauthentik/elements/Base";
+import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
+
+import { msg } from "@lit/localize";
+import { html, nothing } from "lit";
+import { customElement, property } from "lit/decorators.js";
+
+@customElement("ak-license-notice")
+export class AkLicenceNotice extends WithLicenseSummary(AKElement) {
+ @property()
+ notice = msg("This feature requires an enterprise license.");
+
+ render() {
+ return this.hasEnterpriseLicense
+ ? nothing
+ : html`
+
+ ${this.notice}
+ ${msg("Learn more")}
+
+ `;
+ }
+}
diff --git a/web/src/admin/property-mappings/PropertyMappingWizard.ts b/web/src/admin/property-mappings/PropertyMappingWizard.ts
index 4f0ab6122..15dc6047a 100644
--- a/web/src/admin/property-mappings/PropertyMappingWizard.ts
+++ b/web/src/admin/property-mappings/PropertyMappingWizard.ts
@@ -1,9 +1,11 @@
+import "@goauthentik/admin/common/ak-license-notice";
import "@goauthentik/admin/property-mappings/PropertyMappingLDAPForm";
import "@goauthentik/admin/property-mappings/PropertyMappingNotification";
import "@goauthentik/admin/property-mappings/PropertyMappingRACForm";
import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm";
import "@goauthentik/admin/property-mappings/PropertyMappingScopeForm";
import "@goauthentik/admin/property-mappings/PropertyMappingTestForm";
+import { WithLicenseSummary } from "@goauthentik/app/elements/Interface/licenseSummaryProvider";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/forms/ProxyForm";
@@ -14,23 +16,20 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
import { msg, str } from "@lit/localize";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { CSSResult, TemplateResult, html, nothing } from "lit";
-import { property, state } from "lit/decorators.js";
+import { property } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
-import { EnterpriseApi, LicenseSummary, PropertymappingsApi, TypeCreate } from "@goauthentik/api";
+import { PropertymappingsApi, TypeCreate } from "@goauthentik/api";
@customElement("ak-property-mapping-wizard-initial")
-export class InitialPropertyMappingWizardPage extends WizardPage {
+export class InitialPropertyMappingWizardPage extends WithLicenseSummary(WizardPage) {
@property({ attribute: false })
mappingTypes: TypeCreate[] = [];
- @property({ attribute: false })
- enterprise?: LicenseSummary;
-
static get styles(): CSSResult[] {
return [PFBase, PFForm, PFButton, PFRadio];
}
@@ -50,6 +49,7 @@ export class InitialPropertyMappingWizardPage extends WizardPage {
render(): TemplateResult {
return html`
`;
@@ -92,16 +89,10 @@ export class PropertyMappingWizard extends AKElement {
@property({ attribute: false })
mappingTypes: TypeCreate[] = [];
- @state()
- enterprise?: LicenseSummary;
-
async firstUpdated(): Promise {
this.mappingTypes = await new PropertymappingsApi(
DEFAULT_CONFIG,
).propertymappingsAllTypesList();
- this.enterprise = await new EnterpriseApi(
- DEFAULT_CONFIG,
- ).enterpriseLicenseSummaryRetrieve();
}
render(): TemplateResult {
diff --git a/web/src/admin/providers/ProviderWizard.ts b/web/src/admin/providers/ProviderWizard.ts
index 7f19b4d02..ca80f995e 100644
--- a/web/src/admin/providers/ProviderWizard.ts
+++ b/web/src/admin/providers/ProviderWizard.ts
@@ -1,8 +1,10 @@
+import "@goauthentik/admin/common/ak-license-notice";
import "@goauthentik/admin/providers/ldap/LDAPProviderForm";
import "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm";
import "@goauthentik/admin/providers/proxy/ProxyProviderForm";
import "@goauthentik/admin/providers/saml/SAMLProviderForm";
import "@goauthentik/admin/providers/saml/SAMLProviderImportForm";
+import { WithLicenseSummary } from "@goauthentik/app/elements/Interface/licenseSummaryProvider";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/Alert";
import { AKElement } from "@goauthentik/elements/Base";
@@ -15,7 +17,7 @@ import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
import { msg, str } from "@lit/localize";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { CSSResult, TemplateResult, html, nothing } from "lit";
-import { property, state } from "lit/decorators.js";
+import { property } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
@@ -23,16 +25,13 @@ import PFHint from "@patternfly/patternfly/components/Hint/hint.css";
import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
-import { EnterpriseApi, LicenseSummary, ProvidersApi, TypeCreate } from "@goauthentik/api";
+import { ProvidersApi, TypeCreate } from "@goauthentik/api";
@customElement("ak-provider-wizard-initial")
-export class InitialProviderWizardPage extends WizardPage {
+export class InitialProviderWizardPage extends WithLicenseSummary(WizardPage) {
@property({ attribute: false })
providerTypes: TypeCreate[] = [];
- @property({ attribute: false })
- enterprise?: LicenseSummary;
-
static get styles(): CSSResult[] {
return [PFBase, PFForm, PFHint, PFButton, PFRadio];
}
@@ -73,6 +72,7 @@ export class InitialProviderWizardPage extends WizardPage {
render(): TemplateResult {
return html``;
@@ -113,9 +110,6 @@ export class ProviderWizard extends AKElement {
@property({ attribute: false })
providerTypes: TypeCreate[] = [];
- @state()
- enterprise?: LicenseSummary;
-
@property({ attribute: false })
finalHandler: () => Promise = () => {
return Promise.resolve();
@@ -123,9 +117,6 @@ export class ProviderWizard extends AKElement {
async firstUpdated(): Promise {
this.providerTypes = await new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList();
- this.enterprise = await new EnterpriseApi(
- DEFAULT_CONFIG,
- ).enterpriseLicenseSummaryRetrieve();
}
render(): TemplateResult {
@@ -138,11 +129,7 @@ export class ProviderWizard extends AKElement {
return this.finalHandler();
}}
>
-
+
${this.providerTypes.map((type) => {
return html`
diff --git a/web/src/elements/AuthentikContexts.ts b/web/src/elements/AuthentikContexts.ts
index 02fa89316..7e3a1e78b 100644
--- a/web/src/elements/AuthentikContexts.ts
+++ b/web/src/elements/AuthentikContexts.ts
@@ -1,9 +1,13 @@
import { createContext } from "@lit-labs/context";
-import type { Config, CurrentTenant } from "@goauthentik/api";
+import type { Config, CurrentTenant, LicenseSummary } from "@goauthentik/api";
export const authentikConfigContext = createContext(Symbol("authentik-config-context"));
+export const authentikEnterpriseContext = createContext(
+ Symbol("authentik-enterprise-context"),
+);
+
export const authentikTenantContext = createContext(
Symbol("authentik-tenant-context"),
);
diff --git a/web/src/elements/Interface/Interface.ts b/web/src/elements/Interface/Interface.ts
index b2470cfd2..5cdf7a082 100644
--- a/web/src/elements/Interface/Interface.ts
+++ b/web/src/elements/Interface/Interface.ts
@@ -1,7 +1,9 @@
+import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { config, tenant } from "@goauthentik/common/api/config";
import { UIConfig, uiConfig } from "@goauthentik/common/ui/config";
import {
authentikConfigContext,
+ authentikEnterpriseContext,
authentikTenantContext,
} from "@goauthentik/elements/AuthentikContexts";
import type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types";
@@ -12,7 +14,8 @@ import { state } from "lit/decorators.js";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
-import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api";
+import type { Config, CurrentTenant, LicenseSummary } from "@goauthentik/api";
+import { EnterpriseApi, UiThemeEnum } from "@goauthentik/api";
import { AKElement } from "../Base";
@@ -63,11 +66,33 @@ export class Interface extends AKElement implements AkInterface {
return this._tenant;
}
+ _licenseSummaryContext = new ContextProvider(this, {
+ context: authentikEnterpriseContext,
+ initialValue: undefined,
+ });
+
+ _licenseSummary?: LicenseSummary;
+
+ @state()
+ set licenseSummary(c: LicenseSummary) {
+ this._licenseSummary = c;
+ this._licenseSummaryContext.setValue(c);
+ this.requestUpdate();
+ }
+
+ get licenseSummary(): LicenseSummary | undefined {
+ return this._licenseSummary;
+ }
+
constructor() {
super();
document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)];
tenant().then((tenant) => (this.tenant = tenant));
config().then((config) => (this.config = config));
+ new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseSummaryRetrieve().then((enterprise) => {
+ this.licenseSummary = enterprise;
+ });
+
this.dataset.akInterfaceRoot = "true";
}
diff --git a/web/src/elements/Interface/licenseSummaryProvider.ts b/web/src/elements/Interface/licenseSummaryProvider.ts
new file mode 100644
index 000000000..64811ed12
--- /dev/null
+++ b/web/src/elements/Interface/licenseSummaryProvider.ts
@@ -0,0 +1,25 @@
+import { authentikEnterpriseContext } from "@goauthentik/elements/AuthentikContexts";
+
+import { consume } from "@lit-labs/context";
+import type { LitElement } from "lit";
+
+import type { LicenseSummary } from "@goauthentik/api";
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type Constructor = abstract new (...args: any[]) => T;
+
+export function WithLicenseSummary>(
+ superclass: T,
+ subscribe = true,
+) {
+ abstract class WithEnterpriseProvider extends superclass {
+ @consume({ context: authentikEnterpriseContext, subscribe })
+ public licenseSummary!: LicenseSummary;
+
+ get hasEnterpriseLicense() {
+ return this.licenseSummary?.hasLicense;
+ }
+ }
+
+ return WithEnterpriseProvider;
+}
diff --git a/web/src/elements/enterprise/EnterpriseStatusBanner.ts b/web/src/elements/enterprise/EnterpriseStatusBanner.ts
index 09d376759..b3360fb59 100644
--- a/web/src/elements/enterprise/EnterpriseStatusBanner.ts
+++ b/web/src/elements/enterprise/EnterpriseStatusBanner.ts
@@ -1,19 +1,14 @@
-import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { AKElement } from "@goauthentik/elements/Base";
+import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
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 PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
-import { EnterpriseApi, LicenseSummary } from "@goauthentik/api";
-
@customElement("ak-enterprise-status")
-export class EnterpriseStatusBanner extends AKElement {
- @state()
- summary?: LicenseSummary;
-
+export class EnterpriseStatusBanner extends WithLicenseSummary(AKElement) {
@property()
interface: "admin" | "user" | "" = "";
@@ -21,12 +16,10 @@ export class EnterpriseStatusBanner extends AKElement {
return [PFBanner];
}
- async firstUpdated(): Promise {
- this.summary = await new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseSummaryRetrieve();
- }
-
renderBanner(): TemplateResult {
- return html`
+ return html`
`;
@@ -35,12 +28,12 @@ export class EnterpriseStatusBanner extends AKElement {
render(): TemplateResult {
switch (this.interface.toLowerCase()) {
case "admin":
- if (this.summary?.showAdminWarning || this.summary?.readOnly) {
+ if (this.licenseSummary?.showAdminWarning || this.licenseSummary?.readOnly) {
return this.renderBanner();
}
break;
case "user":
- if (this.summary?.showUserWarning || this.summary?.readOnly) {
+ if (this.licenseSummary?.showUserWarning || this.licenseSummary?.readOnly) {
return this.renderBanner();
}
break;