From 14f0034a0aebcece60fb20b5d996cbde918b76bb Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 23 Mar 2023 14:05:14 +0100 Subject: [PATCH] web/elements: only render form once instance is loaded (#5049) * web/elements: only render form once instance is loaded Signed-off-by: Jens Langhammer * use radio for transport Signed-off-by: Jens Langhammer * only wait for instance to be loaded if set Signed-off-by: Jens Langhammer * add hook to load additional data in form Signed-off-by: Jens Langhammer * make send an abstract function instead of attribute Signed-off-by: Jens Langhammer * ensure form is updated after data is loaded Signed-off-by: Jens Langhammer * remove until for select and multi-selects in forms Signed-off-by: Jens Langhammer * don't use until for file uploads Signed-off-by: Jens Langhammer * remove last until from form Signed-off-by: Jens Langhammer * remove deprecated import Signed-off-by: Jens Langhammer * prevent form double load, add error handling for PreventFormSubmit Signed-off-by: Jens Langhammer * fix double creation of inner element in proxy form Signed-off-by: Jens Langhammer * make PreventFormSubmit work correctly Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- web/src/admin/applications/ApplicationForm.ts | 118 +++++++------- web/src/admin/events/RuleForm.ts | 42 +++-- web/src/admin/events/TransportForm.ts | 61 +++----- web/src/admin/flows/FlowForm.ts | 125 +++++++-------- web/src/admin/flows/StageBindingForm.ts | 48 +++--- web/src/admin/outposts/OutpostForm.ts | 144 +++++++----------- .../event_matcher/EventMatcherPolicyForm.ts | 37 +++-- .../providers/oauth2/OAuth2ProviderForm.ts | 121 +++++++-------- .../providers/proxy/ProxyProviderForm.ts | 111 ++++++-------- .../providers/radius/RadiusProviderForm.ts | 4 +- .../radius/RadiusProviderViewPage.ts | 3 +- .../admin/providers/saml/SAMLProviderForm.ts | 63 ++++---- .../admin/providers/scim/SCIMProviderForm.ts | 110 ++++++------- web/src/admin/sources/ldap/LDAPSourceForm.ts | 120 +++++++-------- .../admin/sources/oauth/OAuthSourceForm.ts | 105 ++++++------- web/src/admin/sources/plex/PlexSourceForm.ts | 105 ++++++------- web/src/admin/sources/saml/SAMLSourceForm.ts | 104 ++++++------- .../AuthenticatorValidateStageForm.ts | 62 ++++---- web/src/admin/stages/email/EmailStageForm.ts | 50 +++--- .../identification/IdentificationStageForm.ts | 63 ++++---- .../admin/stages/prompt/PromptStageForm.ts | 91 ++++++----- web/src/elements/Base.ts | 23 ++- web/src/elements/forms/Form.ts | 83 +++++----- web/src/elements/forms/ModelForm.ts | 57 +++++-- web/src/elements/forms/ProxyForm.ts | 8 +- web/src/elements/forms/Radio.ts | 13 +- web/src/elements/forms/SearchSelect.ts | 2 +- web/src/elements/wizard/WizardFormPage.ts | 4 +- web/src/user/UserInterface.ts | 18 +-- 29 files changed, 900 insertions(+), 995 deletions(-) diff --git a/web/src/admin/applications/ApplicationForm.ts b/web/src/admin/applications/ApplicationForm.ts index a9c221de1..a8300e44d 100644 --- a/web/src/admin/applications/ApplicationForm.ts +++ b/web/src/admin/applications/ApplicationForm.ts @@ -1,5 +1,6 @@ import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { first, groupBy } from "@goauthentik/common/utils"; +import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/ModalForm"; @@ -13,7 +14,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { Application, @@ -195,70 +195,58 @@ export class ApplicationForm extends ModelForm { ${t`If checked, the launch URL will open in a new browser tab or window from the user's application library.`}

- ${until( - config().then((c) => { - if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { - return html` - - ${this.instance?.metaIcon - ? html` -

- ${t`Currently set to:`} - ${this.instance?.metaIcon} -

- ` - : html``} -
- ${this.instance?.metaIcon - ? html` - - -

- ${t`Delete currently set icon.`} -

-
- ` - : html``}`; - } - return html` - -

- ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} -

-
`; - }), - )} + ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.SaveMedia) + ? html` + + ${this.instance?.metaIcon + ? html` +

+ ${t`Currently set to:`} ${this.instance?.metaIcon} +

+ ` + : html``} +
+ ${this.instance?.metaIcon + ? html` + + +

+ ${t`Delete currently set icon.`} +

+
+ ` + : html``}` + : html` + +

+ ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} +

+
`} { + eventTransports?: PaginatedNotificationTransportList; + loadInstance(pk: string): Promise { return new EventsApi(DEFAULT_CONFIG).eventsRulesRetrieve({ pbmUuid: pk, }); } + async load(): Promise { + this.eventTransports = await new EventsApi(DEFAULT_CONFIG).eventsTransportsList({ + ordering: "name", + }); + } + getSuccessMessage(): string { if (this.instance) { return t`Successfully updated rule.`; @@ -86,28 +94,14 @@ export class RuleForm extends ModelForm {

${t`Select which transports should be used to notify the user. If none are selected, the notification will only be shown in the authentik UI.`} @@ -120,7 +114,7 @@ export class RuleForm extends ModelForm { { } }; - renderTransportModes(): TemplateResult { - return html` - - - - - `; - } - onModeChange(mode: string | undefined): void { if ( mode === NotificationTransportModeEnum.Webhook || @@ -107,15 +79,32 @@ export class TransportForm extends ModelForm { /> - + { - ${until( - config().then((c) => { - if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { - return html` - - ${this.instance?.background - ? html` -

- ${t`Currently set to:`} - ${this.instance?.background} -

- ` - : html``} -

- ${t`Background shown during execution.`} -

-
- ${this.instance?.background - ? html` - - -

- ${t`Delete currently set background image.`} -

-
- ` - : html``}`; - } - return html` - -

- ${t`Background shown during execution.`} -

-
`; - }), - )} + ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.SaveMedia) + ? html` + + ${this.instance?.background + ? html` +

+ ${t`Currently set to:`} ${this.instance?.background} +

+ ` + : html``} + +

+ ${t`Background shown during execution.`} +

+
+ ${this.instance?.background + ? html` + + +

+ ${t`Delete currently set background image.`} +

+
+ ` + : html``}` + : html` + +

+ ${t`Background shown during execution.`} +

+
`} `; diff --git a/web/src/admin/flows/StageBindingForm.ts b/web/src/admin/flows/StageBindingForm.ts index fc8fdf251..b79c95194 100644 --- a/web/src/admin/flows/StageBindingForm.ts +++ b/web/src/admin/flows/StageBindingForm.ts @@ -1,3 +1,4 @@ +import { RenderFlowOption } from "@goauthentik/admin/flows/utils"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first, groupBy } from "@goauthentik/common/utils"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -10,11 +11,13 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { + Flow, FlowStageBinding, FlowsApi, + FlowsInstancesListDesignationEnum, + FlowsInstancesListRequest, InvalidResponseActionEnum, PolicyEngineMode, Stage, @@ -85,23 +88,32 @@ export class StageBindingForm extends ModelForm { `; } return html` - + => { + const args: FlowsInstancesListRequest = { + ordering: "slug", + designation: FlowsInstancesListDesignationEnum.Authorization, + }; + if (query !== undefined) { + args.search = query; + } + const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList(args); + return flows.results; + }} + .renderElement=${(flow: Flow): string => { + return RenderFlowOption(flow); + }} + .renderDescription=${(flow: Flow): TemplateResult => { + return html`${flow.name}`; + }} + .value=${(flow: Flow | undefined): string | undefined => { + return flow?.pk; + }} + .selected=${(flow: Flow): boolean => { + return flow.pk === this.instance?.target; + }} + > + `; } diff --git a/web/src/admin/outposts/OutpostForm.ts b/web/src/admin/outposts/OutpostForm.ts index 4443c692e..f93627df6 100644 --- a/web/src/admin/outposts/OutpostForm.ts +++ b/web/src/admin/outposts/OutpostForm.ts @@ -10,15 +10,18 @@ import YAML from "yaml"; import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; -import { customElement, property } from "lit/decorators.js"; +import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { Outpost, + OutpostDefaultConfig, OutpostTypeEnum, OutpostsApi, OutpostsServiceConnectionsAllListRequest, + PaginatedLDAPProviderList, + PaginatedProxyProviderList, + PaginatedRadiusProviderList, ProvidersApi, ServiceConnection, } from "@goauthentik/api"; @@ -31,6 +34,14 @@ export class OutpostForm extends ModelForm { @property({ type: Boolean }) embedded = false; + @state() + providers?: + | PaginatedProxyProviderList + | PaginatedLDAPProviderList + | PaginatedRadiusProviderList; + + defaultConfig?: OutpostDefaultConfig; + async loadInstance(pk: string): Promise { const o = await new OutpostsApi(DEFAULT_CONFIG).outpostsInstancesRetrieve({ uuid: pk, @@ -39,6 +50,34 @@ export class OutpostForm extends ModelForm { return o; } + async load(): Promise { + this.defaultConfig = await new OutpostsApi( + DEFAULT_CONFIG, + ).outpostsInstancesDefaultSettingsRetrieve(); + switch (this.type) { + case OutpostTypeEnum.Proxy: + this.providers = await new ProvidersApi(DEFAULT_CONFIG).providersProxyList({ + ordering: "name", + applicationIsnull: false, + }); + break; + case OutpostTypeEnum.Ldap: + this.providers = await new ProvidersApi(DEFAULT_CONFIG).providersLdapList({ + ordering: "name", + applicationIsnull: false, + }); + break; + case OutpostTypeEnum.Radius: + this.providers = await new ProvidersApi(DEFAULT_CONFIG).providersRadiusList({ + ordering: "name", + applicationIsnull: false, + }); + break; + case OutpostTypeEnum.UnknownDefaultOpenApi: + this.providers = undefined; + } + } + getSuccessMessage(): string { if (this.instance) { return t`Successfully updated outpost.`; @@ -60,78 +99,6 @@ export class OutpostForm extends ModelForm { } }; - renderProviders(): Promise { - switch (this.type) { - case OutpostTypeEnum.Proxy: - return new ProvidersApi(DEFAULT_CONFIG) - .providersProxyList({ - ordering: "name", - applicationIsnull: false, - }) - .then((providers) => { - return providers.results.map((provider) => { - const selected = Array.from(this.instance?.providers || []).some( - (sp) => { - return sp == provider.pk; - }, - ); - return html``; - }); - }); - case OutpostTypeEnum.Ldap: - return new ProvidersApi(DEFAULT_CONFIG) - .providersLdapList({ - ordering: "name", - applicationIsnull: false, - }) - .then((providers) => { - return providers.results.map((provider) => { - const selected = Array.from(this.instance?.providers || []).some( - (sp) => { - return sp == provider.pk; - }, - ); - return html``; - }); - }); - case OutpostTypeEnum.Radius: - return new ProvidersApi(DEFAULT_CONFIG) - .providersRadiusList({ - ordering: "name", - applicationIsnull: false, - }) - .then((providers) => { - return providers.results.map((provider) => { - const selected = Array.from(this.instance?.providers || []).some( - (sp) => { - return sp == provider.pk; - }, - ); - return html``; - }); - }); - case OutpostTypeEnum.UnknownDefaultOpenApi: - return Promise.resolve([ - html` `, - ]); - } - } - renderForm(): TemplateResult { return html`
@@ -148,6 +115,7 @@ export class OutpostForm extends ModelForm { @change=${(ev: Event) => { const target = ev.target as HTMLSelectElement; this.type = target.selectedOptions[0].value as OutpostTypeEnum; + this.load(); }} > + @@ -213,7 +187,14 @@ export class OutpostForm extends ModelForm { name="providers" >

${t`You can only select providers that match the type of the outpost.`} @@ -223,19 +204,10 @@ export class OutpostForm extends ModelForm {

-

diff --git a/web/src/admin/policies/event_matcher/EventMatcherPolicyForm.ts b/web/src/admin/policies/event_matcher/EventMatcherPolicyForm.ts index 555f391f4..cb42a789b 100644 --- a/web/src/admin/policies/event_matcher/EventMatcherPolicyForm.ts +++ b/web/src/admin/policies/event_matcher/EventMatcherPolicyForm.ts @@ -10,9 +10,15 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; -import { AdminApi, EventMatcherPolicy, EventsApi, PoliciesApi, TypeCreate } from "@goauthentik/api"; +import { + AdminApi, + App, + EventMatcherPolicy, + EventsApi, + PoliciesApi, + TypeCreate, +} from "@goauthentik/api"; @customElement("ak-policy-event-matcher-form") export class EventMatcherPolicyForm extends ModelForm { @@ -22,6 +28,12 @@ export class EventMatcherPolicyForm extends ModelForm { + this.apps = await new AdminApi(DEFAULT_CONFIG).adminAppsList(); + } + + apps?: App[]; + getSuccessMessage(): string { if (this.instance) { return t`Successfully updated policy.`; @@ -118,19 +130,14 @@ export class EventMatcherPolicyForm extends ModelForm --------- - ${until( - new AdminApi(DEFAULT_CONFIG).adminAppsList().then((apps) => { - return apps.map((app) => { - return html``; - }); - }), - html``, - )} + ${this.apps?.map((app) => { + return html``; + })}

${t`Match events created by selected application. When left empty, all applications are matched.`} diff --git a/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts b/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts index 9d764f8e5..cf539421e 100644 --- a/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts +++ b/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts @@ -11,9 +11,8 @@ import "@goauthentik/elements/utils/TimeDeltaHelp"; import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; -import { customElement, property } from "lit/decorators.js"; +import { customElement, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { CertificateKeyPair, @@ -26,6 +25,8 @@ import { FlowsInstancesListRequest, IssuerModeEnum, OAuth2Provider, + PaginatedOAuthSourceList, + PaginatedScopeMappingList, PropertymappingsApi, ProvidersApi, SourcesApi, @@ -34,19 +35,31 @@ import { @customElement("ak-provider-oauth2-form") export class OAuth2ProviderFormPage extends ModelForm { - loadInstance(pk: number): Promise { - return new ProvidersApi(DEFAULT_CONFIG) - .providersOauth2Retrieve({ - id: pk, - }) - .then((provider) => { - this.showClientSecret = provider.clientType === ClientTypeEnum.Confidential; - return provider; - }); + propertyMappings?: PaginatedScopeMappingList; + oauthSources?: PaginatedOAuthSourceList; + + @state() + showClientSecret = true; + + async loadInstance(pk: number): Promise { + const provider = await new ProvidersApi(DEFAULT_CONFIG).providersOauth2Retrieve({ + id: pk, + }); + this.showClientSecret = provider.clientType === ClientTypeEnum.Confidential; + return provider; } - @property({ type: Boolean }) - showClientSecret = true; + async load(): Promise { + this.propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsScopeList({ + ordering: "scope_name", + }); + this.oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({ + ordering: "name", + hasJwks: true, + }); + } getSuccessMessage(): string { if (this.instance) { @@ -287,36 +300,27 @@ ${this.instance?.redirectUris}

${t`Select which scopes can be used by the client. The client still has to specify the scope to access the data.`} @@ -413,29 +417,14 @@ ${this.instance?.redirectUris}

${t`JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.`} diff --git a/web/src/admin/providers/proxy/ProxyProviderForm.ts b/web/src/admin/providers/proxy/ProxyProviderForm.ts index 3a9155289..dd4ed9461 100644 --- a/web/src/admin/providers/proxy/ProxyProviderForm.ts +++ b/web/src/admin/providers/proxy/ProxyProviderForm.ts @@ -13,7 +13,6 @@ import { CSSResult, css } from "lit"; import { TemplateResult, html } from "lit"; import { customElement, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import PFContent from "@patternfly/patternfly/components/Content/content.css"; import PFList from "@patternfly/patternfly/components/List/list.css"; @@ -28,6 +27,8 @@ import { FlowsApi, FlowsInstancesListDesignationEnum, FlowsInstancesListRequest, + PaginatedOAuthSourceList, + PaginatedScopeMappingList, PropertymappingsApi, ProvidersApi, ProxyMode, @@ -51,18 +52,30 @@ export class ProxyProviderFormPage extends ModelForm { ); } - loadInstance(pk: number): Promise { - return new ProvidersApi(DEFAULT_CONFIG) - .providersProxyRetrieve({ - id: pk, - }) - .then((provider) => { - this.showHttpBasic = first(provider.basicAuthEnabled, true); - this.mode = first(provider.mode, ProxyMode.Proxy); - return provider; - }); + async loadInstance(pk: number): Promise { + const provider = await new ProvidersApi(DEFAULT_CONFIG).providersProxyRetrieve({ + id: pk, + }); + this.showHttpBasic = first(provider.basicAuthEnabled, true); + this.mode = first(provider.mode, ProxyMode.Proxy); + return provider; } + async load(): Promise { + this.propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsScopeList({ + ordering: "scope_name", + }); + this.oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({ + ordering: "name", + hasJwks: true, + }); + } + + propertyMappings?: PaginatedScopeMappingList; + oauthSources?: PaginatedOAuthSourceList; + @state() showHttpBasic = true; @@ -392,34 +405,23 @@ export class ProxyProviderFormPage extends ModelForm { name="propertyMappings" >

${t`Additional scope mappings, which are passed to the proxy.`} @@ -497,29 +499,14 @@ ${this.instance?.skipPathRegex}

${t`JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.`} diff --git a/web/src/admin/providers/radius/RadiusProviderForm.ts b/web/src/admin/providers/radius/RadiusProviderForm.ts index c4ff7e20a..a8566f976 100644 --- a/web/src/admin/providers/radius/RadiusProviderForm.ts +++ b/web/src/admin/providers/radius/RadiusProviderForm.ts @@ -9,9 +9,9 @@ import "@goauthentik/elements/forms/SearchSelect"; import { t } from "@lingui/macro"; -import { customElement } from "lit-element"; -import { TemplateResult, html } from "lit-html"; +import { TemplateResult, html } from "lit"; import { ifDefined } from "lit-html/directives/if-defined.js"; +import { customElement } from "lit/decorators.js"; import { Flow, diff --git a/web/src/admin/providers/radius/RadiusProviderViewPage.ts b/web/src/admin/providers/radius/RadiusProviderViewPage.ts index 67184657b..1e6de7747 100644 --- a/web/src/admin/providers/radius/RadiusProviderViewPage.ts +++ b/web/src/admin/providers/radius/RadiusProviderViewPage.ts @@ -11,7 +11,8 @@ import "@goauthentik/elements/events/ObjectChangelog"; import { t } from "@lingui/macro"; -import { CSSResult, TemplateResult, customElement, html, property } from "lit-element"; +import { CSSResult, TemplateResult, html } from "lit"; +import { customElement, property } from "lit/decorators.js"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFCard from "@patternfly/patternfly/components/Card/card.css"; diff --git a/web/src/admin/providers/saml/SAMLProviderForm.ts b/web/src/admin/providers/saml/SAMLProviderForm.ts index e1f3d9c31..181fafe92 100644 --- a/web/src/admin/providers/saml/SAMLProviderForm.ts +++ b/web/src/admin/providers/saml/SAMLProviderForm.ts @@ -12,7 +12,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { CertificateKeyPair, @@ -23,6 +22,7 @@ import { FlowsApi, FlowsInstancesListDesignationEnum, FlowsInstancesListRequest, + PaginatedSAMLPropertyMappingList, PropertymappingsApi, PropertymappingsSamlListRequest, ProvidersApi, @@ -40,6 +40,16 @@ export class SAMLProviderFormPage extends ModelForm { }); } + async load(): Promise { + this.propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsSamlList({ + ordering: "saml_name", + }); + } + + propertyMappings?: PaginatedSAMLPropertyMappingList; + getSuccessMessage(): string { if (this.instance) { return t`Successfully updated provider.`; @@ -241,36 +251,27 @@ export class SAMLProviderFormPage extends ModelForm { name="propertyMappings" >

${t`Hold control/command to select multiple items.`} diff --git a/web/src/admin/providers/scim/SCIMProviderForm.ts b/web/src/admin/providers/scim/SCIMProviderForm.ts index 867683741..3f7e4b66c 100644 --- a/web/src/admin/providers/scim/SCIMProviderForm.ts +++ b/web/src/admin/providers/scim/SCIMProviderForm.ts @@ -11,12 +11,12 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { CoreApi, CoreGroupsListRequest, Group, + PaginatedSCIMMappingList, PropertymappingsApi, ProvidersApi, SCIMProvider, @@ -30,6 +30,16 @@ export class SCIMProviderFormPage extends ModelForm { }); } + async load(): Promise { + this.propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsScimList({ + ordering: "managed", + }); + } + + propertyMappings?: PaginatedSCIMMappingList; + getSuccessMessage(): string { if (this.instance) { return t`Successfully updated provider.`; @@ -147,36 +157,26 @@ export class SCIMProviderFormPage extends ModelForm { name="propertyMappings" >

${t`Property mappings used to user mapping.`} @@ -191,35 +191,25 @@ export class SCIMProviderFormPage extends ModelForm { name="propertyMappingsGroup" >

${t`Property mappings used to group creation.`} diff --git a/web/src/admin/sources/ldap/LDAPSourceForm.ts b/web/src/admin/sources/ldap/LDAPSourceForm.ts index bffe60f9b..f8df6fde3 100644 --- a/web/src/admin/sources/ldap/LDAPSourceForm.ts +++ b/web/src/admin/sources/ldap/LDAPSourceForm.ts @@ -10,7 +10,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { CertificateKeyPair, @@ -21,6 +20,7 @@ import { Group, LDAPSource, LDAPSourceRequest, + PaginatedLDAPPropertyMappingList, PropertymappingsApi, SourcesApi, } from "@goauthentik/api"; @@ -33,6 +33,16 @@ export class LDAPSourceForm extends ModelForm { }); } + async load(): Promise { + this.propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsLdapList({ + ordering: "managed,object_field", + }); + } + + propertyMappings?: PaginatedLDAPPropertyMappingList; + getSuccessMessage(): string { if (this.instance) { return t`Successfully updated source.`; @@ -241,40 +251,31 @@ export class LDAPSourceForm extends ModelForm { name="propertyMappings" >

${t`Property mappings used to user creation.`} @@ -289,35 +290,26 @@ export class LDAPSourceForm extends ModelForm { name="propertyMappingsGroup" >

${t`Property mappings used to group creation.`} diff --git a/web/src/admin/sources/oauth/OAuthSourceForm.ts b/web/src/admin/sources/oauth/OAuthSourceForm.ts index 6084086f8..ac4fb496a 100644 --- a/web/src/admin/sources/oauth/OAuthSourceForm.ts +++ b/web/src/admin/sources/oauth/OAuthSourceForm.ts @@ -2,6 +2,7 @@ import { RenderFlowOption } from "@goauthentik/admin/flows/utils"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; +import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/CodeMirror"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -13,7 +14,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { CapabilitiesEnum, @@ -315,63 +315,52 @@ export class OAuthSourceForm extends ModelForm { ${t`Path template for users created. Use placeholders like \`%(slug)s\` to insert the source slug.`}

- ${until( - config().then((c) => { - if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { - return html` - - ${this.instance?.icon - ? html` -

- ${t`Currently set to:`} ${this.instance?.icon} -

- ` - : html``} -
- ${this.instance?.icon - ? html` - - - -

- ${t`Delete currently set icon.`} -

-
- ` - : html``}`; - } - return html` - -

- ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} -

-
`; - }), - )} + ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.SaveMedia) + ? html` + + ${this.instance?.icon + ? html` +

+ ${t`Currently set to:`} ${this.instance?.icon} +

+ ` + : html``} +
+ ${this.instance?.icon + ? html` + + +

+ ${t`Delete currently set icon.`} +

+
+ ` + : html``}` + : html` + +

+ ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} +

+
`} ${t`Protocol settings`} diff --git a/web/src/admin/sources/plex/PlexSourceForm.ts b/web/src/admin/sources/plex/PlexSourceForm.ts index 21908febd..8dcc72933 100644 --- a/web/src/admin/sources/plex/PlexSourceForm.ts +++ b/web/src/admin/sources/plex/PlexSourceForm.ts @@ -3,6 +3,7 @@ import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils" import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex"; import { first, randomString } from "@goauthentik/common/utils"; +import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; @@ -13,7 +14,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { CapabilitiesEnum, @@ -267,63 +267,52 @@ export class PlexSourceForm extends ModelForm { ${t`Path template for users created. Use placeholders like \`%(slug)s\` to insert the source slug.`}

- ${until( - config().then((c) => { - if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { - return html` - - ${this.instance?.icon - ? html` -

- ${t`Currently set to:`} ${this.instance?.icon} -

- ` - : html``} -
- ${this.instance?.icon - ? html` - - -

- ${t`Delete currently set icon.`} -

-
- ` - : html``}`; - } - return html` - -

- ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} -

-
`; - }), - )} - + ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.SaveMedia) + ? html` + + ${this.instance?.icon + ? html` +

+ ${t`Currently set to:`} ${this.instance?.icon} +

+ ` + : html``} +
+ ${this.instance?.icon + ? html` + + +

+ ${t`Delete currently set icon.`} +

+
+ ` + : html``}` + : html` + +

+ ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} +

+
`} ${t`Protocol settings`}
diff --git a/web/src/admin/sources/saml/SAMLSourceForm.ts b/web/src/admin/sources/saml/SAMLSourceForm.ts index 6eed32cc5..846698025 100644 --- a/web/src/admin/sources/saml/SAMLSourceForm.ts +++ b/web/src/admin/sources/saml/SAMLSourceForm.ts @@ -2,6 +2,7 @@ import { RenderFlowOption } from "@goauthentik/admin/flows/utils"; import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; +import { rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; @@ -13,7 +14,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { BindingTypeEnum, @@ -161,62 +161,52 @@ export class SAMLSourceForm extends ModelForm { - ${until( - config().then((c) => { - if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { - return html` - - ${this.instance?.icon - ? html` -

- ${t`Currently set to:`} ${this.instance?.icon} -

- ` - : html``} -
- ${this.instance?.icon - ? html` - - -

- ${t`Delete currently set icon.`} -

-
- ` - : html``}`; - } - return html` - -

- ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} -

-
`; - }), - )} + ${rootInterface()?.config?.capabilities.includes(CapabilitiesEnum.SaveMedia) + ? html` + + ${this.instance?.icon + ? html` +

+ ${t`Currently set to:`} ${this.instance?.icon} +

+ ` + : html``} +
+ ${this.instance?.icon + ? html` + + +

+ ${t`Delete currently set icon.`} +

+
+ ` + : html``}` + : html` + +

+ ${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`} +

+
`} ${t`Protocol settings`} diff --git a/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts b/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts index cdd823c25..776873079 100644 --- a/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts +++ b/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts @@ -10,30 +10,35 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { AuthenticatorValidateStage, DeviceClassesEnum, NotConfiguredActionEnum, + PaginatedStageList, StagesApi, UserVerificationEnum, } from "@goauthentik/api"; @customElement("ak-stage-authenticator-validate-form") export class AuthenticatorValidateStageForm extends ModelForm { - loadInstance(pk: string): Promise { - return new StagesApi(DEFAULT_CONFIG) - .stagesAuthenticatorValidateRetrieve({ - stageUuid: pk, - }) - .then((stage) => { - this.showConfigurationStages = - stage.notConfiguredAction === NotConfiguredActionEnum.Configure; - return stage; - }); + async loadInstance(pk: string): Promise { + const stage = await new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorValidateRetrieve({ + stageUuid: pk, + }); + this.showConfigurationStages = + stage.notConfiguredAction === NotConfiguredActionEnum.Configure; + return stage; } + async load(): Promise { + this.stages = await new StagesApi(DEFAULT_CONFIG).stagesAllList({ + ordering: "name", + }); + } + + stages?: PaginatedStageList; + @property({ type: Boolean }) showConfigurationStages = true; @@ -216,28 +221,19 @@ export class AuthenticatorValidateStageForm extends ModelForm

${t`Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again.`} diff --git a/web/src/admin/stages/email/EmailStageForm.ts b/web/src/admin/stages/email/EmailStageForm.ts index d0387a94e..8e30f9bb1 100644 --- a/web/src/admin/stages/email/EmailStageForm.ts +++ b/web/src/admin/stages/email/EmailStageForm.ts @@ -9,23 +9,25 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; -import { EmailStage, StagesApi } from "@goauthentik/api"; +import { EmailStage, StagesApi, TypeCreate } from "@goauthentik/api"; @customElement("ak-stage-email-form") export class EmailStageForm extends ModelForm { - loadInstance(pk: string): Promise { - return new StagesApi(DEFAULT_CONFIG) - .stagesEmailRetrieve({ - stageUuid: pk, - }) - .then((stage) => { - this.showConnectionSettings = !stage.useGlobalSettings; - return stage; - }); + async loadInstance(pk: string): Promise { + const stage = await new StagesApi(DEFAULT_CONFIG).stagesEmailRetrieve({ + stageUuid: pk, + }); + this.showConnectionSettings = !stage.useGlobalSettings; + return stage; } + async load(): Promise { + this.templates = await new StagesApi(DEFAULT_CONFIG).stagesEmailTemplatesList(); + } + + templates?: TypeCreate[]; + @property({ type: Boolean }) showConnectionSettings = false; @@ -232,23 +234,15 @@ export class EmailStageForm extends ModelForm { name="template" >

diff --git a/web/src/admin/stages/identification/IdentificationStageForm.ts b/web/src/admin/stages/identification/IdentificationStageForm.ts index 87b9e65ed..9ab098c4f 100644 --- a/web/src/admin/stages/identification/IdentificationStageForm.ts +++ b/web/src/admin/stages/identification/IdentificationStageForm.ts @@ -11,7 +11,6 @@ import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { until } from "lit/directives/until.js"; import { Flow, @@ -19,6 +18,7 @@ import { FlowsInstancesListDesignationEnum, FlowsInstancesListRequest, IdentificationStage, + PaginatedSourceList, SourcesApi, Stage, StagesApi, @@ -34,6 +34,14 @@ export class IdentificationStageForm extends ModelForm { + this.sources = await new SourcesApi(DEFAULT_CONFIG).sourcesAllList({ + ordering: "slug", + }); + } + + sources?: PaginatedSourceList; + getSuccessMessage(): string { if (this.instance) { return t`Successfully updated stage.`; @@ -80,7 +88,7 @@ export class IdentificationStageForm extends ModelForm ${t`Stage-specific settings`}
-