web: move the license summary information into a top-level context.
Rather than repeatedly fetching the license summary, this commit fetches it once at the top-level and keeps it until an EVENT_REFRESH reaches the top level. This prevents the FOUC (Flash Of Unavailable Content) while loading and awaiting the end of the load.
This commit is contained in:
parent
88dafdcf3e
commit
9dfb0424a4
|
@ -83,7 +83,7 @@ export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
|||
required
|
||||
value="${provider?.connectionExpiry ?? "hours=8"}"
|
||||
help=${msg(
|
||||
"Determines how long a session lasts before being disconnected and requiring re-authorization."
|
||||
"Determines how long a session lasts before being disconnected and requiring re-authorization.",
|
||||
)}
|
||||
required
|
||||
></ak-text-input>
|
||||
|
@ -104,7 +104,7 @@ export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
|||
?selected=${selected.has(mapping.pk)}
|
||||
>
|
||||
${mapping.name}
|
||||
</option>`
|
||||
</option>`,
|
||||
)}
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
|
|
|
@ -1,31 +1,22 @@
|
|||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
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, state } from "lit/decorators.js";
|
||||
|
||||
import { EnterpriseApi } from "@goauthentik/api";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
@customElement("ak-license-notice")
|
||||
export class AkLicenceNotice extends AKElement {
|
||||
@state()
|
||||
hasLicense = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseSummaryRetrieve().then((enterprise) => {
|
||||
this.hasLicense = enterprise.hasLicense;
|
||||
});
|
||||
}
|
||||
export class AkLicenceNotice extends WithLicenseSummary(AKElement) {
|
||||
@property()
|
||||
message = msg("This feature requires an enterprise license.");
|
||||
|
||||
render() {
|
||||
return this.hasLicense
|
||||
return this.hasEnterpriseLicense
|
||||
? nothing
|
||||
: html`
|
||||
<ak-alert class="pf-c-radio__description" inline>
|
||||
${msg("Provider requires enterprise.")}
|
||||
${this.message}
|
||||
<a href="#/enterprise/licenses">${msg("Learn more")}</a>
|
||||
</ak-alert>
|
||||
`;
|
||||
|
|
|
@ -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`<form class="pf-c-form pf-m-horizontal">
|
||||
${this.mappingTypes.map((type) => {
|
||||
const requiresEnteprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
|
||||
return html`<div class="pf-c-radio">
|
||||
<input
|
||||
class="pf-c-radio__input"
|
||||
|
@ -63,20 +63,17 @@ export class InitialPropertyMappingWizardPage extends WizardPage {
|
|||
];
|
||||
this.host.isValid = true;
|
||||
}}
|
||||
?disabled=${type.requiresEnterprise ? !this.enterprise?.hasLicense : false}
|
||||
?disabled=${requiresEnteprise}
|
||||
/>
|
||||
<label class="pf-c-radio__label" for=${`${type.component}-${type.modelName}`}
|
||||
>${type.name}</label
|
||||
>
|
||||
<span class="pf-c-radio__description">${type.description}</span>
|
||||
${type.requiresEnterprise && !this.enterprise?.hasLicense
|
||||
? html`
|
||||
<ak-alert class="pf-c-radio__description" ?inline=${true}>
|
||||
${msg("Provider require enterprise.")}
|
||||
<a href="#/enterprise/licenses">${msg("Learn more")}</a>
|
||||
</ak-alert>
|
||||
`
|
||||
: nothing}
|
||||
<span class="pf-c-radio__description"
|
||||
>${type.description}
|
||||
${requiresEnteprise
|
||||
? html`<ak-license-notice></ak-license-notice>`
|
||||
: nothing}</span
|
||||
>
|
||||
</div>`;
|
||||
})}
|
||||
</form>`;
|
||||
|
@ -92,16 +89,10 @@ export class PropertyMappingWizard extends AKElement {
|
|||
@property({ attribute: false })
|
||||
mappingTypes: TypeCreate[] = [];
|
||||
|
||||
@state()
|
||||
enterprise?: LicenseSummary;
|
||||
|
||||
async firstUpdated(): Promise<void> {
|
||||
this.mappingTypes = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsAllTypesList();
|
||||
this.enterprise = await new EnterpriseApi(
|
||||
DEFAULT_CONFIG,
|
||||
).enterpriseLicenseSummaryRetrieve();
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
|
|
|
@ -4,6 +4,7 @@ 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";
|
||||
|
@ -16,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";
|
||||
|
@ -24,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];
|
||||
}
|
||||
|
@ -74,6 +72,7 @@ export class InitialProviderWizardPage extends WizardPage {
|
|||
render(): TemplateResult {
|
||||
return html`<form class="pf-c-form pf-m-horizontal">
|
||||
${this.providerTypes.map((type) => {
|
||||
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
|
||||
return html`<div class="pf-c-radio">
|
||||
<input
|
||||
class="pf-c-radio__input"
|
||||
|
@ -84,12 +83,12 @@ export class InitialProviderWizardPage extends WizardPage {
|
|||
this.host.steps = ["initial", `type-${type.component}`];
|
||||
this.host.isValid = true;
|
||||
}}
|
||||
?disabled=${type.requiresEnterprise ? !this.enterprise?.hasLicense : false}
|
||||
?disabled=${requiresEnterprise}
|
||||
/>
|
||||
<label class="pf-c-radio__label" for=${type.component}>${type.name}</label>
|
||||
<span class="pf-c-radio__description"
|
||||
>${type.description}
|
||||
${type.requiresEnterprise
|
||||
${requiresEnterprise
|
||||
? html`<ak-license-notice></ak-license-notice>`
|
||||
: nothing}
|
||||
</span>
|
||||
|
@ -111,9 +110,6 @@ export class ProviderWizard extends AKElement {
|
|||
@property({ attribute: false })
|
||||
providerTypes: TypeCreate[] = [];
|
||||
|
||||
@state()
|
||||
enterprise?: LicenseSummary;
|
||||
|
||||
@property({ attribute: false })
|
||||
finalHandler: () => Promise<void> = () => {
|
||||
return Promise.resolve();
|
||||
|
@ -121,9 +117,6 @@ export class ProviderWizard extends AKElement {
|
|||
|
||||
async firstUpdated(): Promise<void> {
|
||||
this.providerTypes = await new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList();
|
||||
this.enterprise = await new EnterpriseApi(
|
||||
DEFAULT_CONFIG,
|
||||
).enterpriseLicenseSummaryRetrieve();
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
|
@ -136,11 +129,7 @@ export class ProviderWizard extends AKElement {
|
|||
return this.finalHandler();
|
||||
}}
|
||||
>
|
||||
<ak-provider-wizard-initial
|
||||
slot="initial"
|
||||
.providerTypes=${this.providerTypes}
|
||||
.enterprise=${this.enterprise}
|
||||
>
|
||||
<ak-provider-wizard-initial slot="initial" .providerTypes=${this.providerTypes}>
|
||||
</ak-provider-wizard-initial>
|
||||
${this.providerTypes.map((type) => {
|
||||
return html`
|
||||
|
|
|
@ -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<Config>(Symbol("authentik-config-context"));
|
||||
|
||||
export const authentikEnterpriseContext = createContext<LicenseSummary>(
|
||||
Symbol("authentik-enterprise-context"),
|
||||
);
|
||||
|
||||
export const authentikTenantContext = createContext<CurrentTenant>(
|
||||
Symbol("authentik-tenant-context"),
|
||||
);
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
25
web/src/elements/Interface/licenseSummaryProvider.ts
Normal file
25
web/src/elements/Interface/licenseSummaryProvider.ts
Normal file
|
@ -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<T = object> = abstract new (...args: any[]) => T;
|
||||
|
||||
export function WithLicenseSummary<T extends Constructor<LitElement>>(
|
||||
superclass: T,
|
||||
subscribe = true
|
||||
) {
|
||||
abstract class WithEnterpriseProvider extends superclass {
|
||||
@consume({ context: authentikEnterpriseContext, subscribe })
|
||||
public licenseSummary!: LicenseSummary;
|
||||
|
||||
get hasEnterpriseLicense() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return WithEnterpriseProvider;
|
||||
}
|
|
@ -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<void> {
|
||||
this.summary = await new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseSummaryRetrieve();
|
||||
}
|
||||
|
||||
renderBanner(): TemplateResult {
|
||||
return html`<div class="pf-c-banner ${this.summary?.readOnly ? "pf-m-red" : "pf-m-gold"}">
|
||||
return html`<div
|
||||
class="pf-c-banner ${this.licenseSummary?.readOnly ? "pf-m-red" : "pf-m-gold"}"
|
||||
>
|
||||
${msg("Warning: The current user count has exceeded the configured licenses.")}
|
||||
<a href="/if/admin/#/enterprise/licenses"> ${msg("Click here for more info.")} </a>
|
||||
</div>`;
|
||||
|
@ -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;
|
||||
|
|
Reference in a new issue