Merge branch 'main' into dev

* main:
  web: upgrade to lit 3 (#8781)
This commit is contained in:
Ken Sternberg
2024-03-11 11:03:04 -07:00
32 changed files with 771 additions and 1042 deletions

1245
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -39,9 +39,10 @@
"@formatjs/intl-listformat": "^7.5.5", "@formatjs/intl-listformat": "^7.5.5",
"@fortawesome/fontawesome-free": "^6.5.1", "@fortawesome/fontawesome-free": "^6.5.1",
"@goauthentik/api": "^2024.2.2-1709583949", "@goauthentik/api": "^2024.2.2-1709583949",
"@lit-labs/context": "^0.4.0",
"@lit-labs/task": "^3.1.0", "@lit-labs/task": "^3.1.0",
"@lit/localize": "^0.11.4", "@lit/reactive-element": "^2.0.4",
"@lit/context": "^1.1.0",
"@lit/localize": "^0.12.1",
"@open-wc/lit-helpers": "^0.7.0", "@open-wc/lit-helpers": "^0.7.0",
"@patternfly/elements": "^2.4.0", "@patternfly/elements": "^2.4.0",
"@patternfly/patternfly": "^4.224.2", "@patternfly/patternfly": "^4.224.2",
@ -56,7 +57,7 @@
"country-flag-icons": "^1.5.9", "country-flag-icons": "^1.5.9",
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"guacamole-common-js": "^1.5.0", "guacamole-common-js": "^1.5.0",
"lit": "^2.8.0", "lit": "^3.1.2",
"md-front-matter": "^1.0.4", "md-front-matter": "^1.0.4",
"mermaid": "^10.9.0", "mermaid": "^10.9.0",
"rapidoc": "^9.3.4", "rapidoc": "^9.3.4",

View File

@ -14,7 +14,7 @@ import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/SpinnerButton"; import "@goauthentik/elements/buttons/SpinnerButton";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
@ -37,37 +37,11 @@ import {
@customElement("ak-application-view") @customElement("ak-application-view")
export class ApplicationViewPage extends AKElement { export class ApplicationViewPage extends AKElement {
@property() @property({ type: String })
set applicationSlug(value: string) { applicationSlug?: string;
new CoreApi(DEFAULT_CONFIG)
.coreApplicationsRetrieve({
slug: value,
})
.then((app) => {
this.application = app;
if (
app.providerObj &&
[
"authentik_providers_proxy.proxyprovider",
"authentik_providers_ldap.ldapprovider",
].includes(app.providerObj.metaModelName)
) {
new OutpostsApi(DEFAULT_CONFIG)
.outpostsInstancesList({
providersByPk: [app.provider || 0],
pageSize: 1,
})
.then((outposts) => {
if (outposts.pagination.count < 1) {
this.missingOutpost = true;
}
});
}
});
}
@property({ attribute: false }) @state()
application!: Application; application?: Application;
@state() @state()
missingOutpost = false; missingOutpost = false;
@ -86,6 +60,40 @@ export class ApplicationViewPage extends AKElement {
]; ];
} }
fetchIsMissingOutpost(providersByPk: Array<number>) {
new OutpostsApi(DEFAULT_CONFIG)
.outpostsInstancesList({
providersByPk,
pageSize: 1,
})
.then((outposts) => {
if (outposts.pagination.count < 1) {
this.missingOutpost = true;
}
});
}
fetchApplication(slug: string) {
new CoreApi(DEFAULT_CONFIG).coreApplicationsRetrieve({ slug }).then((app) => {
this.application = app;
if (
app.providerObj &&
[
RbacPermissionsAssignedByUsersListModelEnum.ProvidersProxyProxyprovider.toString(),
RbacPermissionsAssignedByUsersListModelEnum.ProvidersLdapLdapprovider.toString(),
].includes(app.providerObj.metaModelName)
) {
this.fetchIsMissingOutpost([app.provider || 0]);
}
});
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("applicationSlug") && this.applicationSlug) {
this.fetchApplication(this.applicationSlug);
}
}
render(): TemplateResult { render(): TemplateResult {
return html`<ak-page-header return html`<ak-page-header
header=${this.application?.name || msg("Loading")} header=${this.application?.name || msg("Loading")}

View File

@ -20,8 +20,9 @@ export class AkBackchannelProvidersInput extends AKElement {
// TODO: This abstraction is wrong; it's putting *more* layers in as a way of managing the // TODO: This abstraction is wrong; it's putting *more* layers in as a way of managing the
// visual clutter and legibility issues of ak-form-elemental-horizontal and patternfly in // visual clutter and legibility issues of ak-form-elemental-horizontal and patternfly in
// general. // general.
protected createRenderRoot() { protected createRenderRoot() {
return this; return this as HTMLElement;
} }
@property({ type: String }) @property({ type: String })

View File

@ -4,7 +4,7 @@ import { KeyUnknown, serializeForm } from "@goauthentik/elements/forms/Form";
import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement"; import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter"; import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { consume } from "@lit-labs/context"; import { consume } from "@lit/context";
import { query } from "@lit/reactive-element/decorators.js"; import { query } from "@lit/reactive-element/decorators.js";
import { styles as AwadStyles } from "./BasePanel.css"; import { styles as AwadStyles } from "./BasePanel.css";

View File

@ -1,4 +1,4 @@
import { createContext } from "@lit-labs/context"; import { createContext } from "@lit/context";
import { ApplicationWizardState } from "./types"; import { ApplicationWizardState } from "./types";

View File

@ -1,7 +1,7 @@
import { AkWizard } from "@goauthentik/components/ak-wizard-main/AkWizard"; import { AkWizard } from "@goauthentik/components/ak-wizard-main/AkWizard";
import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter"; import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter";
import { ContextProvider } from "@lit-labs/context"; import { ContextProvider } from "@lit/context";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { customElement, state } from "lit/decorators.js"; import { customElement, state } from "lit/decorators.js";

View File

@ -1,4 +1,4 @@
import { consume } from "@lit-labs/context"; import { consume } from "@lit/context";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { state } from "@lit/reactive-element/decorators/state.js"; import { state } from "@lit/reactive-element/decorators/state.js";
import { LitElement, html } from "lit"; import { LitElement, html } from "lit";

View File

@ -8,8 +8,8 @@ import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/PageHeader"; import "@goauthentik/elements/PageHeader";
import { msg, str } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import PFCard from "@patternfly/patternfly/components/Card/card.css"; import PFCard from "@patternfly/patternfly/components/Card/card.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css"; import PFContent from "@patternfly/patternfly/components/Content/content.css";
@ -22,24 +22,28 @@ import { EventsApi } from "@goauthentik/api";
@customElement("ak-event-view") @customElement("ak-event-view")
export class EventViewPage extends AKElement { export class EventViewPage extends AKElement {
@property() @property({ type: String })
set eventID(value: string) { eventID?: string;
new EventsApi(DEFAULT_CONFIG)
.eventsEventsRetrieve({
eventUuid: value,
})
.then((ev) => {
this.event = ev as EventWithContext;
});
}
@property({ attribute: false }) @state()
event!: EventWithContext; event!: EventWithContext;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFGrid, PFDescriptionList, PFPage, PFContent, PFCard]; return [PFBase, PFGrid, PFDescriptionList, PFPage, PFContent, PFCard];
} }
fetchEvent(eventUuid: string) {
new EventsApi(DEFAULT_CONFIG).eventsEventsRetrieve({ eventUuid }).then((ev) => {
this.event = ev as EventWithContext;
});
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("eventID") && this.eventID) {
this.fetchEvent(this.eventID);
}
}
render(): TemplateResult { render(): TemplateResult {
if (!this.event) { if (!this.event) {
return html`<ak-page-header icon="pf-icon pf-icon-catalog" header=${msg("Loading")}> return html`<ak-page-header icon="pf-icon pf-icon-catalog" header=${msg("Loading")}>

View File

@ -12,8 +12,8 @@ import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/SpinnerButton"; import "@goauthentik/elements/buttons/SpinnerButton";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, css, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, css, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css"; import PFCard from "@patternfly/patternfly/components/Card/card.css";
@ -32,18 +32,10 @@ import {
@customElement("ak-flow-view") @customElement("ak-flow-view")
export class FlowViewPage extends AKElement { export class FlowViewPage extends AKElement {
@property() @property({ type: String })
set flowSlug(value: string) { flowSlug?: string;
new FlowsApi(DEFAULT_CONFIG)
.flowsInstancesRetrieve({
slug: value,
})
.then((flow) => {
this.flow = flow;
});
}
@property({ attribute: false }) @state()
flow!: Flow; flow!: Flow;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
@ -57,6 +49,18 @@ export class FlowViewPage extends AKElement {
`); `);
} }
fetchFlow(slug: string) {
new FlowsApi(DEFAULT_CONFIG).flowsInstancesRetrieve({ slug }).then((flow) => {
this.flow = flow;
});
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("flowSlug") && this.flowSlug) {
this.fetchFlow(this.flowSlug);
}
}
render(): TemplateResult { render(): TemplateResult {
if (!this.flow) { if (!this.flow) {
return html``; return html``;

View File

@ -12,7 +12,7 @@ import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/buttons/SpinnerButton"; import "@goauthentik/elements/buttons/SpinnerButton";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
@ -37,21 +37,10 @@ import {
@customElement("ak-provider-ldap-view") @customElement("ak-provider-ldap-view")
export class LDAPProviderViewPage extends AKElement { export class LDAPProviderViewPage extends AKElement {
@property()
set args(value: { [key: string]: number }) {
this.providerID = value.id;
}
@property({ type: Number }) @property({ type: Number })
set providerID(value: number) { providerID?: number;
new ProvidersApi(DEFAULT_CONFIG)
.providersLdapRetrieve({
id: value,
})
.then((prov) => (this.provider = prov));
}
@property({ attribute: false }) @state()
provider?: LDAPProvider; provider?: LDAPProvider;
@state() @state()
@ -84,6 +73,18 @@ export class LDAPProviderViewPage extends AKElement {
}); });
} }
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG)
.providersLdapRetrieve({ id })
.then((prov) => (this.provider = prov));
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("providerID") && this.providerID) {
this.fetchProvider(this.providerID);
}
}
render(): TemplateResult { render(): TemplateResult {
if (!this.provider) { if (!this.provider) {
return html``; return html``;

View File

@ -25,8 +25,8 @@ import "@goauthentik/elements/buttons/SpinnerButton";
import { getURLParam } from "@goauthentik/elements/router/RouteMatch"; import { getURLParam } from "@goauthentik/elements/router/RouteMatch";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
@ -75,21 +75,10 @@ export function isForward(mode: ProxyMode): boolean {
@customElement("ak-provider-proxy-view") @customElement("ak-provider-proxy-view")
export class ProxyProviderViewPage extends AKElement { export class ProxyProviderViewPage extends AKElement {
@property()
set args(value: { [key: string]: number }) {
this.providerID = value.id;
}
@property({ type: Number }) @property({ type: Number })
set providerID(value: number) { providerID?: number;
new ProvidersApi(DEFAULT_CONFIG)
.providersProxyRetrieve({
id: value,
})
.then((prov) => (this.provider = prov));
}
@property({ attribute: false }) @state()
provider?: ProxyProvider; provider?: ProxyProvider;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
@ -116,6 +105,18 @@ export class ProxyProviderViewPage extends AKElement {
}); });
} }
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG)
.providersProxyRetrieve({ id })
.then((prov) => (this.provider = prov));
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("providerID") && this.providerID) {
this.fetchProvider(this.providerID);
}
}
renderConfig(): TemplateResult { renderConfig(): TemplateResult {
const serves = [ const serves = [
{ {

View File

@ -15,8 +15,8 @@ import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/buttons/SpinnerButton"; import "@goauthentik/elements/buttons/SpinnerButton";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
@ -38,21 +38,10 @@ import {
@customElement("ak-provider-rac-view") @customElement("ak-provider-rac-view")
export class RACProviderViewPage extends AKElement { export class RACProviderViewPage extends AKElement {
@property()
set args(value: { [key: string]: number }) {
this.providerID = value.id;
}
@property({ type: Number }) @property({ type: Number })
set providerID(value: number) { providerID?: number;
new ProvidersApi(DEFAULT_CONFIG)
.providersRacRetrieve({
id: value,
})
.then((prov) => (this.provider = prov));
}
@property({ attribute: false }) @state()
provider?: RACProvider; provider?: RACProvider;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
@ -79,6 +68,18 @@ export class RACProviderViewPage extends AKElement {
}); });
} }
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG)
.providersRacRetrieve({ id })
.then((prov) => (this.provider = prov));
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("providerID") && this.providerID) {
this.fetchProvider(this.providerID);
}
}
render(): TemplateResult { render(): TemplateResult {
if (!this.provider) { if (!this.provider) {
return html``; return html``;

View File

@ -11,8 +11,8 @@ import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/buttons/SpinnerButton"; import "@goauthentik/elements/buttons/SpinnerButton";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css"; import PFCard from "@patternfly/patternfly/components/Card/card.css";
@ -32,21 +32,10 @@ import {
@customElement("ak-provider-radius-view") @customElement("ak-provider-radius-view")
export class RadiusProviderViewPage extends AKElement { export class RadiusProviderViewPage extends AKElement {
@property()
set args(value: { [key: string]: number }) {
this.providerID = value.id;
}
@property({ type: Number }) @property({ type: Number })
set providerID(value: number) { providerID?: number;
new ProvidersApi(DEFAULT_CONFIG)
.providersRadiusRetrieve({
id: value,
})
.then((prov) => (this.provider = prov));
}
@property({ attribute: false }) @state()
provider?: RadiusProvider; provider?: RadiusProvider;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
@ -71,6 +60,18 @@ export class RadiusProviderViewPage extends AKElement {
}); });
} }
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG)
.providersRadiusRetrieve({ id })
.then((prov) => (this.provider = prov));
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("providerID") && this.providerID) {
this.fetchProvider(this.providerID);
}
}
render(): TemplateResult { render(): TemplateResult {
if (!this.provider) { if (!this.provider) {
return html``; return html``;

View File

@ -17,7 +17,7 @@ import "@goauthentik/elements/buttons/SpinnerButton";
import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
@ -55,37 +55,10 @@ interface SAMLPreviewAttribute {
@customElement("ak-provider-saml-view") @customElement("ak-provider-saml-view")
export class SAMLProviderViewPage extends AKElement { export class SAMLProviderViewPage extends AKElement {
@property()
set args(value: { [key: string]: number }) {
this.providerID = value.id;
}
@property({ type: Number }) @property({ type: Number })
set providerID(value: number) { providerID?: number;
new ProvidersApi(DEFAULT_CONFIG)
.providersSamlRetrieve({
id: value,
})
.then((prov) => {
this.provider = prov;
if (prov.signingKp) {
new CryptoApi(DEFAULT_CONFIG)
.cryptoCertificatekeypairsRetrieve({
kpUuid: prov.signingKp,
})
.then((kp) => (this.signer = kp));
}
if (prov.verificationKp) {
new CryptoApi(DEFAULT_CONFIG)
.cryptoCertificatekeypairsRetrieve({
kpUuid: prov.verificationKp,
})
.then((kp) => (this.verifier = kp));
}
});
}
@property({ attribute: false }) @state()
provider?: SAMLProvider; provider?: SAMLProvider;
@state() @state()
@ -138,6 +111,36 @@ export class SAMLProviderViewPage extends AKElement {
}); });
} }
fetchCertificate(kpUuid: string) {
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsRetrieve({ kpUuid });
}
fetchSigningCertificate(kpUuid: string) {
this.fetchCertificate(kpUuid).then((kp) => (this.signer = kp));
}
fetchVerificationCertificate(kpUuid: string) {
this.fetchCertificate(kpUuid).then((kp) => (this.verifier = kp));
}
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG).providersSamlRetrieve({ id }).then((prov) => {
this.provider = prov;
if (this.provider.signingKp) {
this.fetchSigningCertificate(this.provider.signingKp);
}
if (this.provider.verificationKp) {
this.fetchVerificationCertificate(this.provider.verificationKp);
}
});
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("providerID") && this.providerID) {
this.fetchProvider(this.providerID);
}
}
renderRelatedObjects(): TemplateResult { renderRelatedObjects(): TemplateResult {
const relatedObjects = []; const relatedObjects = [];
if (this.provider?.assignedApplicationName) { if (this.provider?.assignedApplicationName) {

View File

@ -11,7 +11,7 @@ import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/ModalButton"; import "@goauthentik/elements/buttons/ModalButton";
import { msg, str } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
@ -37,21 +37,10 @@ import {
@customElement("ak-provider-scim-view") @customElement("ak-provider-scim-view")
export class SCIMProviderViewPage extends AKElement { export class SCIMProviderViewPage extends AKElement {
@property()
set args(value: { [key: string]: number }) {
this.providerID = value.id;
}
@property({ type: Number }) @property({ type: Number })
set providerID(value: number) { providerID?: number;
new ProvidersApi(DEFAULT_CONFIG)
.providersScimRetrieve({
id: value,
})
.then((prov) => (this.provider = prov));
}
@property({ attribute: false }) @state()
provider?: SCIMProvider; provider?: SCIMProvider;
@state() @state()
@ -82,6 +71,18 @@ export class SCIMProviderViewPage extends AKElement {
}); });
} }
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG)
.providersScimRetrieve({ id })
.then((prov) => (this.provider = prov));
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("providerID") && this.providerID) {
this.fetchProvider(this.providerID);
}
}
render(): TemplateResult { render(): TemplateResult {
if (!this.provider) { if (!this.provider) {
return html``; return html``;

View File

@ -15,7 +15,7 @@ import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect"; import "@goauthentik/elements/forms/SearchSelect";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit"; import { PropertyValues, TemplateResult, html } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
@ -40,22 +40,8 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
return source; return source;
} }
_modelName?: string;
@property() @property()
set modelName(v: string | undefined) { modelName?: string;
this._modelName = v;
new SourcesApi(DEFAULT_CONFIG)
.sourcesOauthSourceTypesList({
name: v?.replace("oauthsource", ""),
})
.then((type) => {
this.providerType = type[0];
});
}
get modelName(): string | undefined {
return this._modelName;
}
@property({ attribute: false }) @property({ attribute: false })
providerType: SourceType | null = null; providerType: SourceType | null = null;
@ -97,6 +83,22 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
return source; return source;
} }
fetchProviderType(v: string | undefined) {
new SourcesApi(DEFAULT_CONFIG)
.sourcesOauthSourceTypesList({
name: v?.replace("oauthsource", ""),
})
.then((type) => {
this.providerType = type[0];
});
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("modelName")) {
this.fetchProviderType(this.modelName);
}
}
renderUrlOptions(): TemplateResult { renderUrlOptions(): TemplateResult {
if (!this.providerType?.urlsCustomizable) { if (!this.providerType?.urlsCustomizable) {
return html``; return html``;

View File

@ -13,7 +13,7 @@ import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { Table, TableColumn } from "@goauthentik/elements/table/Table"; import { Table, TableColumn } from "@goauthentik/elements/table/Table";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit"; import { PropertyValues, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { Event, EventsApi } from "@goauthentik/api"; import { Event, EventsApi } from "@goauthentik/api";
@ -31,27 +31,18 @@ export class ObjectChangelog extends Table<Event> {
@property() @property()
targetModelApp?: string; targetModelApp?: string;
private _targetModelName = "";
@property() @property()
set targetModelName(value: string) { targetModelName = "";
this._targetModelName = value;
this.fetch();
}
get targetModelName(): string {
return this._targetModelName;
}
async apiEndpoint(page: number): Promise<PaginatedResponse<Event>> { async apiEndpoint(page: number): Promise<PaginatedResponse<Event>> {
let modelName = this._targetModelName; let modelName = this.targetModelName;
let appName = this.targetModelApp; let appName = this.targetModelApp;
if (this._targetModelName.indexOf(".") !== -1) { if (this.targetModelName.indexOf(".") !== -1) {
const parts = this._targetModelName.split(".", 1); const parts = this.targetModelName.split(".", 1);
appName = parts[0]; appName = parts[0];
modelName = parts[1]; modelName = parts[1];
} }
if (this._targetModelName === "") { if (this.targetModelName === "") {
return Promise.reject(); return Promise.reject();
} }
return new EventsApi(DEFAULT_CONFIG).eventsEventsList({ return new EventsApi(DEFAULT_CONFIG).eventsEventsList({
@ -74,6 +65,12 @@ export class ObjectChangelog extends Table<Event> {
]; ];
} }
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("targetModelName") && this.targetModelName) {
this.fetch();
}
}
row(item: EventWithContext): TemplateResult[] { row(item: EventWithContext): TemplateResult[] {
return [ return [
html`${actionToLabel(item.action)}`, html`${actionToLabel(item.action)}`,

View File

@ -1,4 +1,4 @@
import { createContext } from "@lit-labs/context"; import { createContext } from "@lit/context";
import type { Config, CurrentBrand, LicenseSummary } from "@goauthentik/api"; import type { Config, CurrentBrand, LicenseSummary } from "@goauthentik/api";

View File

@ -11,8 +11,6 @@ import ThemeDark from "@goauthentik/common/styles/theme-dark.css";
import { Config, CurrentBrand, UiThemeEnum } from "@goauthentik/api"; import { Config, CurrentBrand, UiThemeEnum } from "@goauthentik/api";
import { AdoptedStyleSheetsElement } from "./types";
type AkInterface = HTMLElement & { type AkInterface = HTMLElement & {
getTheme: () => Promise<UiThemeEnum>; getTheme: () => Promise<UiThemeEnum>;
brand?: CurrentBrand; brand?: CurrentBrand;
@ -59,19 +57,22 @@ export class AKElement extends LitElement {
super(); super();
} }
protected createRenderRoot(): ShadowRoot | Element { setInitialStyles(root: DocumentOrShadowRoot) {
this.fixElementStyles(); const styleRoot: DocumentOrShadowRoot = (
const root = super.createRenderRoot() as ShadowRoot; "ShadyDOM" in window ? document : root
let styleRoot: AdoptedStyleSheetsElement = root; ) as DocumentOrShadowRoot;
if ("ShadyDOM" in window) {
styleRoot = document;
}
styleRoot.adoptedStyleSheets = adaptCSS([ styleRoot.adoptedStyleSheets = adaptCSS([
...styleRoot.adoptedStyleSheets, ...styleRoot.adoptedStyleSheets,
ensureCSSStyleSheet(AKGlobal), ensureCSSStyleSheet(AKGlobal),
]); ]);
this._initTheme(styleRoot); this._initTheme(styleRoot);
this._initCustomCSS(styleRoot); this._initCustomCSS(styleRoot);
}
protected createRenderRoot() {
this.fixElementStyles();
const root = super.createRenderRoot();
this.setInitialStyles(root as unknown as DocumentOrShadowRoot);
return root; return root;
} }
@ -86,7 +87,7 @@ export class AKElement extends LitElement {
).elementStyles.map(ensureCSSStyleSheet); ).elementStyles.map(ensureCSSStyleSheet);
} }
async _initTheme(root: AdoptedStyleSheetsElement): Promise<void> { async _initTheme(root: DocumentOrShadowRoot): Promise<void> {
// Early activate theme based on media query to prevent light flash // Early activate theme based on media query to prevent light flash
// when dark is preferred // when dark is preferred
this._activateTheme( this._activateTheme(
@ -98,7 +99,7 @@ export class AKElement extends LitElement {
this._applyTheme(root, await this.getTheme()); this._applyTheme(root, await this.getTheme());
} }
private async _initCustomCSS(root: AdoptedStyleSheetsElement): Promise<void> { private async _initCustomCSS(root: DocumentOrShadowRoot): Promise<void> {
const sheets = await fetchCustomCSS(); const sheets = await fetchCustomCSS();
sheets.map((css) => { sheets.map((css) => {
if (css === "") { if (css === "") {
@ -110,7 +111,7 @@ export class AKElement extends LitElement {
}); });
} }
_applyTheme(root: AdoptedStyleSheetsElement, theme?: UiThemeEnum): void { _applyTheme(root: DocumentOrShadowRoot, theme?: UiThemeEnum): void {
if (!theme) { if (!theme) {
theme = UiThemeEnum.Automatic; theme = UiThemeEnum.Automatic;
} }
@ -145,7 +146,7 @@ export class AKElement extends LitElement {
return undefined; return undefined;
} }
_activateTheme(root: AdoptedStyleSheetsElement, theme: UiThemeEnum) { _activateTheme(root: DocumentOrShadowRoot, theme: UiThemeEnum) {
if (theme === this._activeTheme) { if (theme === this._activeTheme) {
return; return;
} }

View File

@ -7,10 +7,9 @@ import {
authentikConfigContext, authentikConfigContext,
authentikEnterpriseContext, authentikEnterpriseContext,
} from "@goauthentik/elements/AuthentikContexts"; } from "@goauthentik/elements/AuthentikContexts";
import type { AdoptedStyleSheetsElement } from "@goauthentik/elements/types";
import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet"; import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet";
import { ContextProvider } from "@lit-labs/context"; import { ContextProvider } from "@lit/context";
import { state } from "lit/decorators.js"; import { state } from "lit/decorators.js";
import PFBase from "@patternfly/patternfly/patternfly-base.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css";
@ -76,9 +75,9 @@ export class Interface extends AKElement implements AkInterface {
this.dataset.akInterfaceRoot = "true"; this.dataset.akInterfaceRoot = "true";
} }
_activateTheme(root: AdoptedStyleSheetsElement, theme: UiThemeEnum): void { _activateTheme(root: DocumentOrShadowRoot, theme: UiThemeEnum): void {
super._activateTheme(root, theme); super._activateTheme(root, theme);
super._activateTheme(document, theme); super._activateTheme(document as unknown as DocumentOrShadowRoot, theme);
} }
async getTheme(): Promise<UiThemeEnum> { async getTheme(): Promise<UiThemeEnum> {

View File

@ -1,6 +1,6 @@
import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts";
import { consume } from "@lit-labs/context"; import { consume } from "@lit/context";
import type { LitElement } from "lit"; import type { LitElement } from "lit";
import type { Config } from "@goauthentik/api"; import type { Config } from "@goauthentik/api";

View File

@ -1,6 +1,6 @@
import { authentikBrandContext } from "@goauthentik/elements/AuthentikContexts"; import { authentikBrandContext } from "@goauthentik/elements/AuthentikContexts";
import { consume } from "@lit-labs/context"; import { consume } from "@lit/context";
import type { LitElement } from "lit"; import type { LitElement } from "lit";
import type { CurrentBrand } from "@goauthentik/api"; import type { CurrentBrand } from "@goauthentik/api";

View File

@ -1,6 +1,6 @@
import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts";
import { consume } from "@lit-labs/context"; import { consume } from "@lit/context";
import type { LitElement } from "lit"; import type { LitElement } from "lit";
import { CapabilitiesEnum } from "@goauthentik/api"; import { CapabilitiesEnum } from "@goauthentik/api";

View File

@ -1,6 +1,6 @@
import { authentikEnterpriseContext } from "@goauthentik/elements/AuthentikContexts"; import { authentikEnterpriseContext } from "@goauthentik/elements/AuthentikContexts";
import { consume } from "@lit-labs/context"; import { consume } from "@lit/context";
import type { LitElement } from "lit"; import type { LitElement } from "lit";
import type { LicenseSummary } from "@goauthentik/api"; import type { LicenseSummary } from "@goauthentik/api";

View File

@ -13,8 +13,8 @@ import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
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";
import { CSSResult, TemplateResult, css, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, css, html } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css"; import PFContent from "@patternfly/patternfly/components/Content/content.css";
@ -35,29 +35,11 @@ export class PageHeader extends WithBrandConfig(AKElement) {
hasNotifications = false; hasNotifications = false;
@property() @property()
set header(value: string) { header = "";
const currentIf = currentInterface();
let title = this.brand?.brandingTitle || TITLE_DEFAULT;
if (currentIf === "admin") {
title = `${msg("Admin")} - ${title}`;
}
if (value !== "") {
title = `${value} - ${title}`;
}
document.title = title;
this._header = value;
}
get header(): string {
return this._header;
}
@property() @property()
description?: string; description?: string;
@state()
_header = "";
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [ return [
PFBase, PFBase,
@ -125,6 +107,23 @@ export class PageHeader extends WithBrandConfig(AKElement) {
}); });
} }
setTitle(value: string) {
const currentIf = currentInterface();
const title = this.brand?.brandingTitle || TITLE_DEFAULT;
document.title =
currentIf === "admin"
? `${msg("Admin")} - ${title}`
: value !== ""
? `${value} - ${title}`
: title;
}
willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("header") && this.header) {
this.setTitle(this.header);
}
}
renderIcon(): TemplateResult { renderIcon(): TemplateResult {
if (this.icon) { if (this.icon) {
if (this.iconImage && !this.icon.startsWith("fa://")) { if (this.iconImage && !this.icon.startsWith("fa://")) {

View File

@ -50,7 +50,7 @@ export class TreeViewNode extends AKElement {
return pathItems.reverse().join(this.separator); return pathItems.reverse().join(this.separator);
} }
protected createRenderRoot(): Element { protected createRenderRoot() {
return this; return this;
} }
@ -171,8 +171,7 @@ export class TreeView extends AKElement {
} }
return item; return item;
} else { } else {
const child = this.createNode(path, parentItem.childItems[idx], level + 1); return this.createNode(path, parentItem.childItems[idx], level + 1);
return child;
} }
} }

View File

@ -77,8 +77,9 @@ export class AkDualSelectProvider extends CustomListenerElement(AKElement) {
if (changedProperties.has("provider")) { if (changedProperties.has("provider")) {
this.pagination = undefined; this.pagination = undefined;
if (changedProperties.get("provider")) { const previousProvider = changedProperties.get("provider");
this.selectedMap.set(changedProperties.get("provider"), this.selected); if (previousProvider) {
this.selectedMap.set(previousProvider, this.selected);
this.selected = this.selectedMap.get(this.provider) ?? []; this.selected = this.selectedMap.get(this.provider) ?? [];
} }
this.fetch(); this.fetch();

View File

@ -1,4 +1,4 @@
import { createContext } from "@lit-labs/context"; import { createContext } from "@lit/context";
export const localeContext = createContext<string>("locale"); export const localeContext = createContext<string>("locale");
export default localeContext; export default localeContext;

View File

@ -3,7 +3,7 @@ import { AKElement } from "@goauthentik/elements/Base";
import { PFSize } from "@goauthentik/elements/Spinner"; import { PFSize } from "@goauthentik/elements/Spinner";
import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter"; import { CustomEmitterElement } from "@goauthentik/elements/utils/eventEmitter";
import { Task, TaskStatus } from "@lit-labs/task"; import { Task, TaskStatus } from "@lit/task";
import { css, html } from "lit"; import { css, html } from "lit";
import { property } from "lit/decorators.js"; import { property } from "lit/decorators.js";

View File

@ -1,3 +0,0 @@
export interface AdoptedStyleSheetsElement {
adoptedStyleSheets: readonly CSSStyleSheet[];
}

View File

@ -18,7 +18,7 @@ import "@goauthentik/flow/stages/RedirectStage";
import { StageHost, SubmitOptions } from "@goauthentik/flow/stages/base"; import { StageHost, SubmitOptions } from "@goauthentik/flow/stages/base";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, css, html, nothing } from "lit"; import { CSSResult, PropertyValues, TemplateResult, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js"; import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { until } from "lit/directives/until.js"; import { until } from "lit/directives/until.js";
@ -72,24 +72,8 @@ export class FlowExecutor extends Interface implements StageHost {
@state() @state()
inspectorOpen = false; inspectorOpen = false;
_flowInfo?: ContextualFlowInfo;
@state() @state()
set flowInfo(value: ContextualFlowInfo | undefined) { flowInfo?: ContextualFlowInfo;
this._flowInfo = value;
if (!value) {
return;
}
this.shadowRoot
?.querySelectorAll<HTMLDivElement>(".pf-c-background-image")
.forEach((bg) => {
bg.style.setProperty("--ak-flow-background", `url('${value?.background}')`);
});
}
get flowInfo(): ContextualFlowInfo | undefined {
return this._flowInfo;
}
ws: WebsocketClient; ws: WebsocketClient;
@ -218,10 +202,7 @@ export class FlowExecutor extends Interface implements StageHost {
if (this.challenge.flowInfo) { if (this.challenge.flowInfo) {
this.flowInfo = this.challenge.flowInfo; this.flowInfo = this.challenge.flowInfo;
} }
if (this.challenge.responseErrors) { return !this.challenge.responseErrors;
return false;
}
return true;
} catch (exc: unknown) { } catch (exc: unknown) {
this.errorMessage(exc as Error | ResponseError); this.errorMessage(exc as Error | ResponseError);
return false; return false;
@ -274,6 +255,24 @@ export class FlowExecutor extends Interface implements StageHost {
this.challenge = challenge as ChallengeTypes; this.challenge = challenge as ChallengeTypes;
} }
setShadowStyles(value: ContextualFlowInfo) {
if (!value) {
return;
}
this.shadowRoot
?.querySelectorAll<HTMLDivElement>(".pf-c-background-image")
.forEach((bg) => {
bg.style.setProperty("--ak-flow-background", `url('${value?.background}')`);
});
}
// DOM post-processing has to happen after the render.
updated(changedProperties: PropertyValues<this>) {
if (changedProperties.has("flowInfo") && this.flowInfo !== undefined) {
this.setShadowStyles(this.flowInfo);
}
}
async renderChallengeNativeElement(): Promise<TemplateResult> { async renderChallengeNativeElement(): Promise<TemplateResult> {
switch (this.challenge?.component) { switch (this.challenge?.component) {
case "ak-stage-access-denied": case "ak-stage-access-denied":