web/admin: bugfix: dual select initialization revision (#12051)
* web: Add InvalidationFlow to Radius Provider dialogues ## What - Bugfix: adds the InvalidationFlow to the Radius Provider dialogues - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated to the Notification. - Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/` ## Note Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current dialogues at the moment. * Start of dual select revision process. * Progress. * Made the RuleFormHelper's dualselect conform. * Providers and Selectors harmonized for sources. * web/bugfix/dual-select-full-options # What - Replaces the dual-select "selected" list mechanism with a more comprehensive (if computationally expensive) version that is correct. # How In the previous iteration, each dual select controller gets a *provider* and a *selector*; the latter keeps the keys of all the objects a specific instance may have, and marks those objects as "selected" when they appear in the dual-selects "selected" panel. In order to distinguish between "selected on the existing instance" and "selected by the user," the *selector* only runs at construction time, creating a unified "selected" list; this is standard and allows for a uniform experience of adding and deleting items. Unfortunately, this means that the "selected" items, because their displays are crafted bespoke, are only chosen from those available at construction. If there are selected items later in the paginated collection, they will not be marked as selected. This defeats the purpose of having a paginated multi-select! The correct way to do this is to retrieve every item pased to the *selector* and use the same algorithm to craft the views in both windows. For every instance of Dual Select with dynamic selection, the *provider* and *selector* have been put in a separate file (usually suffixed as a `*FormHelper.ts` file); the algorithm by which an item is crafted for use by DualSelect has been broken out into a small function (usually named `*toSelect()`). The *provider* works as before. The *selector* takes every instance key passed to it and runs a `Promise.allSettled(...*Retrieve({ uuid: instanceId }))` on them, mapping them onto the `selected` collection using the same `*toSelect()`, so they resemble the possibilities in every way. # Lessons This exercise emphasizes just how much sheer *repetition* the Django REST API creates on the client side. Every Helper file is a copy-pasta of a sibling, with only a few minor changes: - How the objects are turned into displays for DualSelect - The type and calls being used; - The field on which retrival is defined - The defaulting rule. There are 19 `*FormHelper` files, and each one is 50 lines long. That's 950 lines of code. Of those 950 lines of code, 874 of those lines are *complete duplicates* of those in the other FormHelper files. Only 76 lines are unique. This language really needs macros. That, or I need to seriously level up my Typescript and figure out how to make this whole thing a lot smarter. * order fields by field_key and order Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
@ -1,23 +1,23 @@
|
||||
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
||||
import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
||||
import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
|
||||
import {
|
||||
makeOAuth2PropertyMappingsSelector,
|
||||
oauth2PropertyMappingsProvider,
|
||||
} from "@goauthentik/admin/providers/oauth2/OAuth2PropertyMappings.js";
|
||||
import {
|
||||
clientTypeOptions,
|
||||
issuerModeOptions,
|
||||
redirectUriHelp,
|
||||
subjectModeOptions,
|
||||
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm";
|
||||
import {
|
||||
propertyMappingsProvider,
|
||||
propertyMappingsSelector,
|
||||
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderFormHelpers.js";
|
||||
import {
|
||||
IRedirectURIInput,
|
||||
akOAuthRedirectURIInput,
|
||||
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderRedirectURI";
|
||||
import {
|
||||
makeSourceSelector,
|
||||
oauth2SourcesProvider,
|
||||
oauth2SourcesSelector,
|
||||
} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
|
||||
@ -252,10 +252,8 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
|
||||
.errorMessages=${errors?.propertyMappings ?? []}
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${oauth2PropertyMappingsProvider}
|
||||
.selector=${makeOAuth2PropertyMappingsSelector(
|
||||
provider?.propertyMappings,
|
||||
)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(provider?.propertyMappings)}
|
||||
available-label=${msg("Available Scopes")}
|
||||
selected-label=${msg("Selected Scopes")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
@ -309,7 +307,7 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${oauth2SourcesProvider}
|
||||
.selector=${makeSourceSelector(provider?.jwksSources)}
|
||||
.selector=${oauth2SourcesSelector(provider?.jwksSources)}
|
||||
available-label=${msg("Available Sources")}
|
||||
selected-label=${msg("Selected Sources")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
||||
import {
|
||||
makeSourceSelector,
|
||||
oauth2SourcesProvider,
|
||||
oauth2SourcesSelector,
|
||||
} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js";
|
||||
import {
|
||||
makeProxyPropertyMappingsSelector,
|
||||
proxyPropertyMappingsProvider,
|
||||
} from "@goauthentik/admin/providers/proxy/ProxyProviderPropertyMappings.js";
|
||||
propertyMappingsProvider,
|
||||
propertyMappingsSelector,
|
||||
} from "@goauthentik/admin/providers/proxy/ProxyProviderFormHelpers.js";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
@ -147,8 +147,8 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${proxyPropertyMappingsProvider}
|
||||
.selector=${makeProxyPropertyMappingsSelector(
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available Scopes")}"
|
||||
@ -248,7 +248,7 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${oauth2SourcesProvider}
|
||||
.selector=${makeSourceSelector(this.instance?.jwksSources)}
|
||||
.selector=${oauth2SourcesSelector(this.instance?.jwksSources)}
|
||||
available-label=${msg("Available Sources")}
|
||||
selected-label=${msg("Selected Sources")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import "@goauthentik/admin/applications/wizard/ak-wizard-title";
|
||||
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
||||
import {
|
||||
makeRACPropertyMappingsSelector,
|
||||
racPropertyMappingsProvider,
|
||||
} from "@goauthentik/admin/providers/rac/RACPropertyMappings.js";
|
||||
propertyMappingsProvider,
|
||||
propertyMappingsSelector,
|
||||
} from "@goauthentik/admin/providers/rac/RACProviderFormHelpers.js";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
@ -70,10 +70,8 @@ export class ApplicationWizardAuthenticationByRAC extends BaseProviderPanel {
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${racPropertyMappingsProvider}
|
||||
.selector=${makeRACPropertyMappingsSelector(
|
||||
provider?.propertyMappings,
|
||||
)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(provider?.propertyMappings)}
|
||||
available-label="${msg("Available Property Mappings")}"
|
||||
selected-label="${msg("Selected Property Mappings")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { severityToLabel } from "@goauthentik/common/labels";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
@ -18,32 +17,12 @@ import {
|
||||
EventsApi,
|
||||
Group,
|
||||
NotificationRule,
|
||||
NotificationTransport,
|
||||
PaginatedNotificationTransportList,
|
||||
SeverityEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function eventTransportsProvider(page = 1, search = "") {
|
||||
const eventTransports = await new EventsApi(DEFAULT_CONFIG).eventsTransportsList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
import { eventTransportsProvider, eventTransportsSelector } from "./RuleFormHelpers.js";
|
||||
|
||||
return {
|
||||
pagination: eventTransports.pagination,
|
||||
options: eventTransports.results.map((transport) => [transport.pk, transport.name]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeTransportSelector(instanceTransports: string[] | undefined) {
|
||||
const localTransports = instanceTransports ? new Set(instanceTransports) : undefined;
|
||||
|
||||
return localTransports
|
||||
? ([pk, _]: DualSelectPair) => localTransports.has(pk)
|
||||
: ([_0, _1, _2, stage]: DualSelectPair<NotificationTransport>) => stage !== undefined;
|
||||
}
|
||||
@customElement("ak-event-rule-form")
|
||||
export class RuleForm extends ModelForm<NotificationRule, string> {
|
||||
eventTransports?: PaginatedNotificationTransportList;
|
||||
@ -126,7 +105,7 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${eventTransportsProvider}
|
||||
.selector=${makeTransportSelector(this.instance?.transports)}
|
||||
.selector=${eventTransportsSelector(this.instance?.transports)}
|
||||
available-label="${msg("Available Transports")}"
|
||||
selected-label="${msg("Selected Transports")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
42
web/src/admin/events/RuleFormHelpers.ts
Normal file
42
web/src/admin/events/RuleFormHelpers.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
|
||||
|
||||
import { EventsApi, NotificationTransport } from "@goauthentik/api";
|
||||
|
||||
const transportToSelect = (transport: NotificationTransport) => [transport.pk, transport.name];
|
||||
|
||||
export async function eventTransportsProvider(page = 1, search = "") {
|
||||
const eventTransports = await new EventsApi(DEFAULT_CONFIG).eventsTransportsList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: eventTransports.pagination,
|
||||
options: eventTransports.results.map(transportToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function eventTransportsSelector(instanceTransports: string[] | undefined) {
|
||||
if (!instanceTransports) {
|
||||
return async (transports: DualSelectPair<NotificationTransport>[]) =>
|
||||
transports.filter(
|
||||
([_0, _1, _2, stage]: DualSelectPair<NotificationTransport>) => stage !== undefined,
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const transportsApi = new EventsApi(DEFAULT_CONFIG);
|
||||
const transports = await Promise.allSettled(
|
||||
instanceTransports.map((instanceId) =>
|
||||
transportsApi.eventsTransportsRetrieve({ uuid: instanceId }),
|
||||
),
|
||||
);
|
||||
return transports
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(transportToSelect);
|
||||
};
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||
import {
|
||||
googleWorkspacePropertyMappingsProvider,
|
||||
makeGoogleWorkspacePropertyMappingsSelector,
|
||||
} from "@goauthentik/admin/providers/google_workspace/GoogleWorkspaceProviderPropertyMappings";
|
||||
propertyMappingsProvider,
|
||||
propertyMappingsSelector,
|
||||
} from "@goauthentik/admin/providers/google_workspace/GoogleWorkspaceProviderFormHelpers.js";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
@ -224,8 +224,8 @@ export class GoogleWorkspaceProviderFormPage extends BaseProviderForm<GoogleWork
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${googleWorkspacePropertyMappingsProvider}
|
||||
.selector=${makeGoogleWorkspacePropertyMappingsSelector(
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
"goauthentik.io/providers/google_workspace/user",
|
||||
)}
|
||||
@ -241,8 +241,8 @@ export class GoogleWorkspaceProviderFormPage extends BaseProviderForm<GoogleWork
|
||||
name="propertyMappingsGroup"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${googleWorkspacePropertyMappingsProvider}
|
||||
.selector=${makeGoogleWorkspacePropertyMappingsSelector(
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.propertyMappingsGroup,
|
||||
"goauthentik.io/providers/google_workspace/group",
|
||||
)}
|
||||
|
@ -0,0 +1,48 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { GoogleWorkspaceProviderMapping, PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: GoogleWorkspaceProviderMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderGoogleWorkspaceList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(
|
||||
instanceMappings: string[] | undefined,
|
||||
defaultSelection: string,
|
||||
) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<GoogleWorkspaceProviderMapping>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, mapping]: DualSelectPair<GoogleWorkspaceProviderMapping>) =>
|
||||
mapping?.managed === defaultSelection,
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderGoogleWorkspaceRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api";
|
||||
|
||||
export async function googleWorkspacePropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderGoogleWorkspaceList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((scope) => [scope.pk, scope.name, scope.name, scope]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeGoogleWorkspacePropertyMappingsSelector(
|
||||
instanceMappings: string[] | undefined,
|
||||
defaultSelection: string,
|
||||
) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
|
||||
scope?.managed === defaultSelection;
|
||||
}
|
46
web/src/admin/providers/ldap/LDAPProviderFormHelpers.ts
Normal file
46
web/src/admin/providers/ldap/LDAPProviderFormHelpers.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { LDAPSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: LDAPSourcePropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceLdapList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (transports: DualSelectPair<LDAPSourcePropertyMapping>[]) =>
|
||||
transports.filter(
|
||||
([_0, _1, _2, mapping]: DualSelectPair<LDAPSourcePropertyMapping>) =>
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/default") ||
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/ms"),
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsSourceLdapRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||
import {
|
||||
makeMicrosoftEntraPropertyMappingsSelector,
|
||||
microsoftEntraPropertyMappingsProvider,
|
||||
} from "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderPropertyMappings";
|
||||
propertyMappingsProvider,
|
||||
propertyMappingsSelector,
|
||||
} from "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderFormHelpers.js";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
@ -213,8 +213,8 @@ export class MicrosoftEntraProviderFormPage extends BaseProviderForm<MicrosoftEn
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${microsoftEntraPropertyMappingsProvider}
|
||||
.selector=${makeMicrosoftEntraPropertyMappingsSelector(
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
"goauthentik.io/providers/microsoft_entra/user",
|
||||
)}
|
||||
@ -230,8 +230,8 @@ export class MicrosoftEntraProviderFormPage extends BaseProviderForm<MicrosoftEn
|
||||
name="propertyMappingsGroup"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${microsoftEntraPropertyMappingsProvider}
|
||||
.selector=${makeMicrosoftEntraPropertyMappingsSelector(
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.propertyMappingsGroup,
|
||||
"goauthentik.io/providers/microsoft_entra/group",
|
||||
)}
|
||||
|
@ -0,0 +1,48 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { MicrosoftEntraProviderMapping, PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: MicrosoftEntraProviderMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderMicrosoftEntraList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(
|
||||
instanceMappings: string[] | undefined,
|
||||
defaultSelection: string,
|
||||
) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<MicrosoftEntraProviderMapping>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, mapping]: DualSelectPair<MicrosoftEntraProviderMapping>) =>
|
||||
mapping?.managed === defaultSelection,
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderMicrosoftEntraRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api";
|
||||
|
||||
export const defaultScopes = [
|
||||
"goauthentik.io/providers/oauth2/scope-openid",
|
||||
"goauthentik.io/providers/oauth2/scope-email",
|
||||
"goauthentik.io/providers/oauth2/scope-profile",
|
||||
];
|
||||
|
||||
export async function oauth2PropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScopeList({
|
||||
ordering: "scope_name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((scope) => [scope.pk, scope.name, scope.name, scope]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeOAuth2PropertyMappingsSelector(instanceMappings: string[] | undefined) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
|
||||
scope?.managed && defaultScopes.includes(scope?.managed);
|
||||
}
|
@ -35,11 +35,8 @@ import {
|
||||
SubModeEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
import {
|
||||
makeOAuth2PropertyMappingsSelector,
|
||||
oauth2PropertyMappingsProvider,
|
||||
} from "./OAuth2PropertyMappings.js";
|
||||
import { makeSourceSelector, oauth2SourcesProvider } from "./OAuth2Sources.js";
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./OAuth2ProviderFormHelpers.js";
|
||||
import { oauth2SourcesProvider, oauth2SourcesSelector } from "./OAuth2Sources.js";
|
||||
|
||||
export const clientTypeOptions = [
|
||||
{
|
||||
@ -335,10 +332,8 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
|
||||
</ak-text-input>
|
||||
<ak-form-element-horizontal label=${msg("Scopes")} name="propertyMappings">
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${oauth2PropertyMappingsProvider}
|
||||
.selector=${makeOAuth2PropertyMappingsSelector(
|
||||
provider?.propertyMappings,
|
||||
)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(provider?.propertyMappings)}
|
||||
available-label=${msg("Available Scopes")}
|
||||
selected-label=${msg("Selected Scopes")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
@ -391,7 +386,7 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${oauth2SourcesProvider}
|
||||
.selector=${makeSourceSelector(provider?.jwksSources)}
|
||||
.selector=${oauth2SourcesSelector(provider?.jwksSources)}
|
||||
available-label=${msg("Available Sources")}
|
||||
selected-label=${msg("Selected Sources")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
51
web/src/admin/providers/oauth2/OAuth2ProviderFormHelpers.ts
Normal file
51
web/src/admin/providers/oauth2/OAuth2ProviderFormHelpers.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api";
|
||||
|
||||
export const defaultScopes = [
|
||||
"goauthentik.io/providers/oauth2/scope-openid",
|
||||
"goauthentik.io/providers/oauth2/scope-email",
|
||||
"goauthentik.io/providers/oauth2/scope-profile",
|
||||
];
|
||||
|
||||
const mappingToSelect = (s: ScopeMapping) => [s.pk, s.name, s.name, s];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScopeList({
|
||||
ordering: "scope_name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<ScopeMapping>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
|
||||
scope?.managed && defaultScopes.includes(scope?.managed),
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderScopeRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -3,6 +3,13 @@ import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
|
||||
|
||||
import { OAuthSource, SourcesApi } from "@goauthentik/api";
|
||||
|
||||
const sourceToSelect = (source: OAuthSource) => [
|
||||
source.pk,
|
||||
`${source.name} (${source.slug})`,
|
||||
source.name,
|
||||
source,
|
||||
];
|
||||
|
||||
export async function oauth2SourcesProvider(page = 1, search = "") {
|
||||
const oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({
|
||||
ordering: "name",
|
||||
@ -14,17 +21,29 @@ export async function oauth2SourcesProvider(page = 1, search = "") {
|
||||
|
||||
return {
|
||||
pagination: oauthSources.pagination,
|
||||
options: oauthSources.results.map((source) => [
|
||||
source.pk,
|
||||
`${source.name} (${source.slug})`,
|
||||
]),
|
||||
options: oauthSources.results.map(sourceToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeSourceSelector(instanceSources: string[] | undefined) {
|
||||
const localSources = instanceSources ? new Set(instanceSources) : undefined;
|
||||
|
||||
return localSources
|
||||
? ([pk, _]: DualSelectPair) => localSources.has(pk)
|
||||
: ([_0, _1, _2, prompt]: DualSelectPair<OAuthSource>) => prompt !== undefined;
|
||||
export function oauth2SourcesSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<OAuthSource>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, source]: DualSelectPair<OAuthSource>) => source !== undefined,
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const oauthSources = new SourcesApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
oauthSources.sourcesOauthRetrieve({ slug: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(sourceToSelect);
|
||||
};
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search";
|
||||
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
|
||||
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
|
||||
import {
|
||||
makeSourceSelector,
|
||||
oauth2SourcesProvider,
|
||||
oauth2SourcesSelector,
|
||||
} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
@ -30,10 +30,7 @@ import {
|
||||
ProxyProvider,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
import {
|
||||
makeProxyPropertyMappingsSelector,
|
||||
proxyPropertyMappingsProvider,
|
||||
} from "./ProxyProviderPropertyMappings.js";
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./ProxyProviderFormHelpers.js";
|
||||
|
||||
@customElement("ak-provider-proxy-form")
|
||||
export class ProxyProviderFormPage extends BaseProviderForm<ProxyProvider> {
|
||||
@ -302,10 +299,8 @@ export class ProxyProviderFormPage extends BaseProviderForm<ProxyProvider> {
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${proxyPropertyMappingsProvider}
|
||||
.selector=${makeProxyPropertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(this.instance?.propertyMappings)}
|
||||
available-label="${msg("Available Scopes")}"
|
||||
selected-label="${msg("Selected Scopes")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
@ -394,7 +389,7 @@ ${this.instance?.skipPathRegex}</textarea
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${oauth2SourcesProvider}
|
||||
.selector=${makeSourceSelector(this.instance?.jwksSources)}
|
||||
.selector=${oauth2SourcesSelector(this.instance?.jwksSources)}
|
||||
available-label=${msg("Available Sources")}
|
||||
selected-label=${msg("Selected Sources")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
45
web/src/admin/providers/proxy/ProxyProviderFormHelpers.ts
Normal file
45
web/src/admin/providers/proxy/ProxyProviderFormHelpers.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (s: ScopeMapping) => [s.pk, s.name, s.name, s];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScopeList({
|
||||
ordering: "scope_name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<ScopeMapping>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
|
||||
!(scope?.managed ?? "").startsWith("goauthentik.io/providers"),
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderScopeRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api";
|
||||
|
||||
export async function proxyPropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScopeList({
|
||||
ordering: "scope_name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((scope) => [scope.pk, scope.name, scope.name, scope]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeProxyPropertyMappingsSelector(mappings?: string[]) {
|
||||
const localMappings = mappings ? new Set(mappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
|
||||
!(scope?.managed ?? "").startsWith("goauthentik.io/providers");
|
||||
}
|
@ -15,10 +15,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { AuthModeEnum, Endpoint, ProtocolEnum, RacApi } from "@goauthentik/api";
|
||||
|
||||
import {
|
||||
makeRACPropertyMappingsSelector,
|
||||
racPropertyMappingsProvider,
|
||||
} from "./RACPropertyMappings.js";
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./RACProviderFormHelpers.js";
|
||||
|
||||
@customElement("ak-rac-endpoint-form")
|
||||
export class EndpointForm extends ModelForm<Endpoint, string> {
|
||||
@ -114,8 +111,8 @@ export class EndpointForm extends ModelForm<Endpoint, string> {
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Property mappings")} name="propertyMappings">
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${racPropertyMappingsProvider}
|
||||
.selector=${makeRACPropertyMappingsSelector(this.instance?.propertyMappings)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(this.instance?.propertyMappings)}
|
||||
available-label="${msg("Available User Property Mappings")}"
|
||||
selected-label="${msg("Selected User Property Mappings")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
@ -1,24 +0,0 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
export async function racPropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderRacList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((mapping) => [mapping.pk, mapping.name]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeRACPropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = new Set(instanceMappings ?? []);
|
||||
return ([pk, _]: DualSelectPair) => localMappings.has(pk);
|
||||
}
|
@ -19,10 +19,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { FlowsInstancesListDesignationEnum, ProvidersApi, RACProvider } from "@goauthentik/api";
|
||||
|
||||
import {
|
||||
makeRACPropertyMappingsSelector,
|
||||
racPropertyMappingsProvider,
|
||||
} from "./RACPropertyMappings.js";
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./RACProviderFormHelpers.js";
|
||||
|
||||
@customElement("ak-provider-rac-form")
|
||||
export class RACProviderFormPage extends ModelForm<RACProvider, number> {
|
||||
@ -127,10 +124,8 @@ export class RACProviderFormPage extends ModelForm<RACProvider, number> {
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${racPropertyMappingsProvider}
|
||||
.selector=${makeRACPropertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(this.instance?.propertyMappings)}
|
||||
available-label="${msg("Available Property Mappings")}"
|
||||
selected-label="${msg("Selected Property Mappings")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
41
web/src/admin/providers/rac/RACProviderFormHelpers.ts
Normal file
41
web/src/admin/providers/rac/RACProviderFormHelpers.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, RACPropertyMapping } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: RACPropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderRacList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (_mappings: DualSelectPair<RACPropertyMapping>[]) => [];
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderRacRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -4,7 +4,6 @@ import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -14,35 +13,9 @@ import { TemplateResult, html } from "lit";
|
||||
import { ifDefined } from "lit-html/directives/if-defined.js";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
import {
|
||||
FlowsInstancesListDesignationEnum,
|
||||
PropertymappingsApi,
|
||||
ProvidersApi,
|
||||
RadiusProvider,
|
||||
RadiusProviderPropertyMapping,
|
||||
} from "@goauthentik/api";
|
||||
import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api";
|
||||
|
||||
export async function radiusPropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderRadiusList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeRadiusPropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, _]: DualSelectPair<RadiusProviderPropertyMapping>) => [];
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./RadiusProviderFormHelpers.js";
|
||||
|
||||
@customElement("ak-provider-radius-form")
|
||||
export class RadiusProviderFormPage extends WithBrandConfig(BaseProviderForm<RadiusProvider>) {
|
||||
@ -155,10 +128,8 @@ export class RadiusProviderFormPage extends WithBrandConfig(BaseProviderForm<Rad
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${radiusPropertyMappingsProvider}
|
||||
.selector=${makeRadiusPropertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(this.instance?.propertyMappings)}
|
||||
available-label=${msg("Available Property Mappings")}
|
||||
selected-label=${msg("Selected Property Mappings")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
41
web/src/admin/providers/radius/RadiusProviderFormHelpers.ts
Normal file
41
web/src/admin/providers/radius/RadiusProviderFormHelpers.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, RadiusProviderPropertyMapping } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: RadiusProviderPropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderRadiusList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (_mappings: DualSelectPair<RadiusProviderPropertyMapping>[]) => [];
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderRadiusRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -9,7 +9,6 @@ import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
@ -31,28 +30,7 @@ import {
|
||||
SpBindingEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
export async function samlPropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderSamlList({
|
||||
ordering: "saml_name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeSAMLPropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, mapping]: DualSelectPair<SAMLPropertyMapping>) =>
|
||||
mapping?.managed?.startsWith("goauthentik.io/providers/saml");
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./SAMLProviderFormHelpers.js";
|
||||
|
||||
@customElement("ak-provider-saml-form")
|
||||
export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
|
||||
@ -303,10 +281,8 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
|
||||
name="propertyMappings"
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${samlPropertyMappingsProvider}
|
||||
.selector=${makeSAMLPropertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
)}
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(this.instance?.propertyMappings)}
|
||||
available-label=${msg("Available User Property Mappings")}
|
||||
selected-label=${msg("Selected User Property Mappings")}
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
44
web/src/admin/providers/saml/SAMLProviderFormHelpers.ts
Normal file
44
web/src/admin/providers/saml/SAMLProviderFormHelpers.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, SAMLPropertyMapping } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: SAMLPropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderSamlList({
|
||||
ordering: "saml_name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<SAMLPropertyMapping>[]) =>
|
||||
mappings.filter(([_0, _1, _2, mapping]: DualSelectPair<SAMLPropertyMapping>) =>
|
||||
mapping?.managed?.startsWith("goauthentik.io/providers/saml"),
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderSamlRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -2,7 +2,6 @@ import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
@ -17,37 +16,11 @@ import {
|
||||
CoreApi,
|
||||
CoreGroupsListRequest,
|
||||
Group,
|
||||
PropertymappingsApi,
|
||||
ProvidersApi,
|
||||
SCIMMapping,
|
||||
SCIMProvider,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
export async function scimPropertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScimList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeSCIMPropertyMappingsSelector(
|
||||
instanceMappings: string[] | undefined,
|
||||
defaultSelected: string,
|
||||
) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, mapping]: DualSelectPair<SCIMMapping>) =>
|
||||
mapping?.managed === defaultSelected;
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./SCIMProviderFormHelpers.js";
|
||||
|
||||
@customElement("ak-provider-scim-form")
|
||||
export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
||||
@ -189,8 +162,8 @@ export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
||||
label=${msg("User Property Mappings")}
|
||||
name="propertyMappings">
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${scimPropertyMappingsProvider}
|
||||
.selector=${makeSCIMPropertyMappingsSelector(
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.propertyMappings,
|
||||
"goauthentik.io/providers/scim/user",
|
||||
)}
|
||||
@ -206,8 +179,8 @@ export class SCIMProviderFormPage extends BaseProviderForm<SCIMProvider> {
|
||||
label=${msg("Group Property Mappings")}
|
||||
name="propertyMappingsGroup">
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${scimPropertyMappingsProvider}
|
||||
.selector=${makeSCIMPropertyMappingsSelector(
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.propertyMappingsGroup,
|
||||
"goauthentik.io/providers/scim/group",
|
||||
)}
|
||||
|
48
web/src/admin/providers/scim/SCIMProviderFormHelpers.ts
Normal file
48
web/src/admin/providers/scim/SCIMProviderFormHelpers.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, SCIMMapping } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: SCIMMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsProviderScimList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(
|
||||
instanceMappings: string[] | undefined,
|
||||
defaultSelected: string,
|
||||
) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<SCIMMapping>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, mapping]: DualSelectPair<SCIMMapping>) =>
|
||||
mapping?.managed === defaultSelected,
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsProviderScimRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -15,7 +15,6 @@ import {
|
||||
WithCapabilitiesConfig,
|
||||
} from "@goauthentik/elements/Interface/capabilitiesProvider";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -29,37 +28,12 @@ import {
|
||||
FlowsInstancesListDesignationEnum,
|
||||
GroupMatchingModeEnum,
|
||||
KerberosSource,
|
||||
KerberosSourcePropertyMapping,
|
||||
KerberosSourceRequest,
|
||||
PropertymappingsApi,
|
||||
SourcesApi,
|
||||
UserMatchingModeEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceKerberosList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
function makePropertyMappingsSelector(object: string, instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, mapping]: DualSelectPair<KerberosSourcePropertyMapping>) =>
|
||||
object == "user" &&
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/kerberos/user/default/");
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./KerberosSourceFormHelpers.js";
|
||||
|
||||
@customElement("ak-source-kerberos-form")
|
||||
export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<KerberosSource>) {
|
||||
@ -323,7 +297,7 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
"user",
|
||||
this.instance?.userPropertyMappings,
|
||||
)}
|
||||
@ -340,7 +314,7 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
"group",
|
||||
this.instance?.groupPropertyMappings,
|
||||
)}
|
||||
|
46
web/src/admin/sources/kerberos/KerberosSourceFormHelpers.ts
Normal file
46
web/src/admin/sources/kerberos/KerberosSourceFormHelpers.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { KerberosSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: KerberosSourcePropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceKerberosList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(object: string, instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<KerberosSourcePropertyMapping>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, mapping]: DualSelectPair<KerberosSourcePropertyMapping>) =>
|
||||
object == "user" &&
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/kerberos/user/default/"),
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsSourceKerberosRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -4,7 +4,6 @@ import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -19,36 +18,11 @@ import {
|
||||
CoreGroupsListRequest,
|
||||
Group,
|
||||
LDAPSource,
|
||||
LDAPSourcePropertyMapping,
|
||||
LDAPSourceRequest,
|
||||
PropertymappingsApi,
|
||||
SourcesApi,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceLdapList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
function makePropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, mapping]: DualSelectPair<LDAPSourcePropertyMapping>) =>
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/default") ||
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/ms");
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./LDAPSourceFormHelpers.js";
|
||||
|
||||
@customElement("ak-source-ldap-form")
|
||||
export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||
@ -296,7 +270,7 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.userPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available User Property Mappings")}"
|
||||
@ -312,7 +286,7 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.groupPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available Group Property Mappings")}"
|
||||
|
46
web/src/admin/sources/ldap/LDAPSourceFormHelpers.ts
Normal file
46
web/src/admin/sources/ldap/LDAPSourceFormHelpers.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { LDAPSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: LDAPSourcePropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceLdapList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (transports: DualSelectPair<LDAPSourcePropertyMapping>[]) =>
|
||||
transports.filter(
|
||||
([_0, _1, _2, mapping]: DualSelectPair<LDAPSourcePropertyMapping>) =>
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/default") ||
|
||||
mapping?.managed?.startsWith("goauthentik.io/sources/ldap/ms"),
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsSourceLdapRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -14,7 +14,6 @@ import {
|
||||
WithCapabilitiesConfig,
|
||||
} from "@goauthentik/elements/Interface/capabilitiesProvider";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -28,36 +27,14 @@ import {
|
||||
FlowsInstancesListDesignationEnum,
|
||||
GroupMatchingModeEnum,
|
||||
OAuthSource,
|
||||
OAuthSourcePropertyMapping,
|
||||
OAuthSourceRequest,
|
||||
PropertymappingsApi,
|
||||
ProviderTypeEnum,
|
||||
SourceType,
|
||||
SourcesApi,
|
||||
UserMatchingModeEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceOauthList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
function makePropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, _]: DualSelectPair<OAuthSourcePropertyMapping>) => false;
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./OAuthSourceFormHelpers.js";
|
||||
|
||||
@customElement("ak-source-oauth-form")
|
||||
export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuthSource>) {
|
||||
@ -467,7 +444,7 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.userPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available User Property Mappings")}"
|
||||
@ -483,7 +460,7 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.groupPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available Group Property Mappings")}"
|
||||
|
44
web/src/admin/sources/oauth/OAuthSourceFormHelpers.ts
Normal file
44
web/src/admin/sources/oauth/OAuthSourceFormHelpers.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { OAuthSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: OAuthSourcePropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceOauthList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<OAuthSourcePropertyMapping>[]) =>
|
||||
mappings.filter(
|
||||
([_0, _1, _2, _3]: DualSelectPair<OAuthSourcePropertyMapping>) => false,
|
||||
);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsSourceOauthRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -15,7 +15,6 @@ import {
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -29,33 +28,11 @@ import {
|
||||
FlowsInstancesListDesignationEnum,
|
||||
GroupMatchingModeEnum,
|
||||
PlexSource,
|
||||
PlexSourcePropertyMapping,
|
||||
PropertymappingsApi,
|
||||
SourcesApi,
|
||||
UserMatchingModeEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourcePlexList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
function makePropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, _]: DualSelectPair<PlexSourcePropertyMapping>) => false;
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./PlexSourceFormHelpers.js";
|
||||
|
||||
@customElement("ak-source-plex-form")
|
||||
export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSource>) {
|
||||
@ -420,7 +397,7 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.userPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available User Property Mappings")}"
|
||||
@ -436,7 +413,7 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.groupPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available Group Property Mappings")}"
|
||||
|
42
web/src/admin/sources/plex/PlexSourceFormHelpers.ts
Normal file
42
web/src/admin/sources/plex/PlexSourceFormHelpers.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PlexSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: PlexSourcePropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourcePlexList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<PlexSourcePropertyMapping>[]) =>
|
||||
mappings.filter(([_0, _1, _2, _3]: DualSelectPair<PlexSourcePropertyMapping>) => false);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsSourcePlexRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -13,7 +13,6 @@ import {
|
||||
WithCapabilitiesConfig,
|
||||
} from "@goauthentik/elements/Interface/capabilitiesProvider";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
@ -30,35 +29,13 @@ import {
|
||||
FlowsInstancesListDesignationEnum,
|
||||
GroupMatchingModeEnum,
|
||||
NameIdPolicyEnum,
|
||||
PropertymappingsApi,
|
||||
SAMLSource,
|
||||
SAMLSourcePropertyMapping,
|
||||
SignatureAlgorithmEnum,
|
||||
SourcesApi,
|
||||
UserMatchingModeEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceSamlList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
function makePropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, _]: DualSelectPair<SAMLSourcePropertyMapping>) => false;
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./SAMLSourceFormHelpers.js";
|
||||
|
||||
@customElement("ak-source-saml-form")
|
||||
export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSource>) {
|
||||
@ -532,7 +509,7 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.userPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available User Property Mappings")}"
|
||||
@ -548,7 +525,7 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.groupPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available Group Property Mappings")}"
|
||||
|
42
web/src/admin/sources/saml/SAMLSourceFormHelpers.ts
Normal file
42
web/src/admin/sources/saml/SAMLSourceFormHelpers.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, SAMLSourcePropertyMapping } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: SAMLSourcePropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceSamlList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<SAMLSourcePropertyMapping>[]) =>
|
||||
mappings.filter(([_0, _1, _2, _4]: DualSelectPair<SAMLSourcePropertyMapping>) => false);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsSourceSamlRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -3,7 +3,6 @@ import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
|
||||
@ -12,35 +11,9 @@ import { TemplateResult, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import {
|
||||
PropertymappingsApi,
|
||||
SCIMSource,
|
||||
SCIMSourcePropertyMapping,
|
||||
SCIMSourceRequest,
|
||||
SourcesApi,
|
||||
} from "@goauthentik/api";
|
||||
import { SCIMSource, SCIMSourceRequest, SourcesApi } from "@goauthentik/api";
|
||||
|
||||
async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceScimList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
|
||||
};
|
||||
}
|
||||
|
||||
function makePropertyMappingsSelector(instanceMappings?: string[]) {
|
||||
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
|
||||
return localMappings
|
||||
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
|
||||
: ([_0, _1, _2, _]: DualSelectPair<SCIMSourcePropertyMapping>) => false;
|
||||
}
|
||||
import { propertyMappingsProvider, propertyMappingsSelector } from "./SCIMSourceFormHelpers.js";
|
||||
|
||||
@customElement("ak-source-scim-form")
|
||||
export class SCIMSourceForm extends BaseSourceForm<SCIMSource> {
|
||||
@ -104,7 +77,7 @@ export class SCIMSourceForm extends BaseSourceForm<SCIMSource> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.userPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available User Property Mappings")}"
|
||||
@ -120,7 +93,7 @@ export class SCIMSourceForm extends BaseSourceForm<SCIMSource> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${propertyMappingsProvider}
|
||||
.selector=${makePropertyMappingsSelector(
|
||||
.selector=${propertyMappingsSelector(
|
||||
this.instance?.groupPropertyMappings,
|
||||
)}
|
||||
available-label="${msg("Available Group Property Mappings")}"
|
||||
|
42
web/src/admin/sources/scim/SCIMSourceFormHelpers.ts
Normal file
42
web/src/admin/sources/scim/SCIMSourceFormHelpers.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { PropertymappingsApi, SCIMSourcePropertyMapping } from "@goauthentik/api";
|
||||
|
||||
const mappingToSelect = (m: SCIMSourcePropertyMapping) => [m.pk, m.name, m.name, m];
|
||||
|
||||
export async function propertyMappingsProvider(page = 1, search = "") {
|
||||
const propertyMappings = await new PropertymappingsApi(
|
||||
DEFAULT_CONFIG,
|
||||
).propertymappingsSourceScimList({
|
||||
ordering: "managed",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
return {
|
||||
pagination: propertyMappings.pagination,
|
||||
options: propertyMappings.results.map(mappingToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function propertyMappingsSelector(instanceMappings?: string[]) {
|
||||
if (!instanceMappings) {
|
||||
return async (mappings: DualSelectPair<SCIMSourcePropertyMapping>[]) =>
|
||||
mappings.filter(([_0, _1, _2, _3]: DualSelectPair<SCIMSourcePropertyMapping>) => false);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const pm = new PropertymappingsApi(DEFAULT_CONFIG);
|
||||
const mappings = await Promise.allSettled(
|
||||
instanceMappings.map((instanceId) =>
|
||||
pm.propertymappingsSourceScimRetrieve({ pmUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
|
||||
return mappings
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(mappingToSelect);
|
||||
};
|
||||
}
|
@ -4,7 +4,6 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import "@goauthentik/elements/Alert";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/Radio";
|
||||
@ -20,47 +19,15 @@ import {
|
||||
DeviceClassesEnum,
|
||||
NotConfiguredActionEnum,
|
||||
PaginatedStageList,
|
||||
Stage,
|
||||
StagesApi,
|
||||
UserVerificationEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function stagesProvider(page = 1, search = "") {
|
||||
const stages = await new StagesApi(DEFAULT_CONFIG).stagesAllList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: stages.pagination,
|
||||
options: stages.results.map((stage) => [stage.pk, `${stage.name} (${stage.verboseName})`]),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeStageSelector(instanceStages: string[] | undefined) {
|
||||
const localStages = instanceStages ? new Set(instanceStages) : undefined;
|
||||
|
||||
return localStages
|
||||
? ([pk, _]: DualSelectPair) => localStages.has(pk)
|
||||
: ([_0, _1, _2, stage]: DualSelectPair<Stage>) => stage !== undefined;
|
||||
}
|
||||
|
||||
async function authenticatorWebauthnDeviceTypesListProvider(page = 1, search = "") {
|
||||
const devicetypes = await new StagesApi(
|
||||
DEFAULT_CONFIG,
|
||||
).stagesAuthenticatorWebauthnDeviceTypesList({
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: devicetypes.pagination,
|
||||
options: devicetypes.results.map(deviceTypeRestrictionPair),
|
||||
};
|
||||
}
|
||||
import {
|
||||
authenticatorWebauthnDeviceTypesListProvider,
|
||||
stagesProvider,
|
||||
stagesSelector,
|
||||
} from "./AuthenticatorValidateStageFormHelpers.js";
|
||||
|
||||
@customElement("ak-stage-authenticator-validate-form")
|
||||
export class AuthenticatorValidateStageForm extends BaseStageForm<AuthenticatorValidateStage> {
|
||||
@ -218,7 +185,7 @@ export class AuthenticatorValidateStageForm extends BaseStageForm<AuthenticatorV
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${stagesProvider}
|
||||
.selector=${makeStageSelector(
|
||||
.selector=${stagesSelector(
|
||||
this.instance?.configurationStages,
|
||||
)}
|
||||
available-label="${msg("Available Stages")}"
|
||||
|
@ -0,0 +1,55 @@
|
||||
import { deviceTypeRestrictionPair } from "@goauthentik/admin/stages/authenticator_webauthn/utils";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { Stage, StagesApi } from "@goauthentik/api";
|
||||
|
||||
const stageToSelect = (stage: Stage) => [stage.pk, `${stage.name} (${stage.verboseName})`];
|
||||
|
||||
export async function stagesProvider(page = 1, search = "") {
|
||||
const stages = await new StagesApi(DEFAULT_CONFIG).stagesAllList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: stages.pagination,
|
||||
options: stages.results.map(stageToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function stagesSelector(instanceStages: string[] | undefined) {
|
||||
if (!instanceStages) {
|
||||
return async (stages: DualSelectPair<Stage>[]) =>
|
||||
stages.filter(([_0, _1, _2, stage]: DualSelectPair<Stage>) => stage !== undefined);
|
||||
}
|
||||
return async () => {
|
||||
const stagesApi = new StagesApi(DEFAULT_CONFIG);
|
||||
const stages = await Promise.allSettled(
|
||||
instanceStages.map((instanceId) =>
|
||||
stagesApi.stagesAllRetrieve({ stageUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
return stages
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(stageToSelect);
|
||||
};
|
||||
}
|
||||
|
||||
export async function authenticatorWebauthnDeviceTypesListProvider(page = 1, search = "") {
|
||||
const devicetypes = await new StagesApi(
|
||||
DEFAULT_CONFIG,
|
||||
).stagesAuthenticatorWebauthnDeviceTypesList({
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: devicetypes.pagination,
|
||||
options: devicetypes.results.map(deviceTypeRestrictionPair),
|
||||
};
|
||||
}
|
@ -4,7 +4,6 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first, groupBy } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/ak-checkbox-group/ak-checkbox-group.js";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/SearchSelect";
|
||||
@ -17,8 +16,6 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
import {
|
||||
FlowsInstancesListDesignationEnum,
|
||||
IdentificationStage,
|
||||
Source,
|
||||
SourcesApi,
|
||||
Stage,
|
||||
StagesApi,
|
||||
StagesCaptchaListRequest,
|
||||
@ -26,31 +23,7 @@ import {
|
||||
UserFieldsEnum,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
async function sourcesProvider(page = 1, search = "") {
|
||||
const sources = await new SourcesApi(DEFAULT_CONFIG).sourcesAllList({
|
||||
ordering: "slug",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: sources.pagination,
|
||||
options: sources.results
|
||||
.filter((source) => source.component !== "")
|
||||
.map((source) => [source.pk, source.name, source.name, source]),
|
||||
};
|
||||
}
|
||||
|
||||
function makeSourcesSelector(instanceSources: string[] | undefined) {
|
||||
const localSources = instanceSources ? new Set(instanceSources) : undefined;
|
||||
|
||||
return localSources
|
||||
? ([pk, _]: DualSelectPair) => localSources.has(pk)
|
||||
: // Creating a new instance, auto-select built-in source only when no other sources exist
|
||||
([_0, _1, _2, source]: DualSelectPair<Source>) =>
|
||||
source !== undefined && source.component === "";
|
||||
}
|
||||
import { sourcesProvider, sourcesSelector } from "./IdentificationStageFormHelpers.js";
|
||||
|
||||
@customElement("ak-stage-identification-form")
|
||||
export class IdentificationStageForm extends BaseStageForm<IdentificationStage> {
|
||||
@ -259,7 +232,7 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage>
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${sourcesProvider}
|
||||
.selector=${makeSourcesSelector(this.instance?.sources)}
|
||||
.selector=${sourcesSelector(this.instance?.sources)}
|
||||
available-label="${msg("Available Sources")}"
|
||||
selected-label="${msg("Selected Sources")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
@ -0,0 +1,39 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { Source, SourcesApi } from "@goauthentik/api";
|
||||
|
||||
const sourceToSelect = (source: Source) => [source.pk, source.name, source.name, source];
|
||||
|
||||
export async function sourcesProvider(page = 1, search = "") {
|
||||
const sources = await new SourcesApi(DEFAULT_CONFIG).sourcesAllList({
|
||||
ordering: "slug",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: sources.pagination,
|
||||
options: sources.results.filter((source) => source.component !== "").map(sourceToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function sourcesSelector(instanceSources: string[] | undefined) {
|
||||
if (!instanceSources) {
|
||||
return async (sources: DualSelectPair<Source>[]) =>
|
||||
sources.filter(([_0, _1, _2, source]: DualSelectPair<Source>) => source !== undefined);
|
||||
}
|
||||
return async () => {
|
||||
const sourcesApi = new SourcesApi(DEFAULT_CONFIG);
|
||||
const sources = await Promise.allSettled(
|
||||
instanceSources.map((instanceId) =>
|
||||
sourcesApi.sourcesAllRetrieve({ slug: instanceId }),
|
||||
),
|
||||
);
|
||||
return sources
|
||||
.filter((s) => s.status === "fulfilled")
|
||||
.map((s) => s.value)
|
||||
.map(sourceToSelect);
|
||||
};
|
||||
}
|
@ -3,67 +3,23 @@ import "@goauthentik/admin/stages/prompt/PromptForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { PFSize } from "@goauthentik/common/enums";
|
||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import "@goauthentik/elements/forms/ModalForm";
|
||||
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html, nothing } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import { PoliciesApi, Policy, Prompt, PromptStage, StagesApi } from "@goauthentik/api";
|
||||
import { PromptStage, StagesApi } from "@goauthentik/api";
|
||||
|
||||
async function promptFieldsProvider(page = 1, search = "") {
|
||||
const prompts = await new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({
|
||||
ordering: "field_name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: prompts.pagination,
|
||||
options: prompts.results.map((prompt) => [
|
||||
prompt.pk,
|
||||
msg(str`${prompt.name} ("${prompt.fieldKey}", of type ${prompt.type})`),
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function makeFieldSelector(instanceFields: string[] | undefined) {
|
||||
const localFields = instanceFields ? new Set(instanceFields) : undefined;
|
||||
|
||||
return localFields
|
||||
? ([pk, _]: DualSelectPair) => localFields.has(pk)
|
||||
: ([_0, _1, _2, prompt]: DualSelectPair<Prompt>) => prompt !== undefined;
|
||||
}
|
||||
|
||||
async function policiesProvider(page = 1, search = "") {
|
||||
const policies = await new PoliciesApi(DEFAULT_CONFIG).policiesAllList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: policies.pagination,
|
||||
options: policies.results.map((policy) => [
|
||||
policy.pk,
|
||||
`${policy.name} (${policy.verboseName})`,
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function makePoliciesSelector(instancePolicies: string[] | undefined) {
|
||||
const localPolicies = instancePolicies ? new Set(instancePolicies) : undefined;
|
||||
|
||||
return localPolicies
|
||||
? ([pk, _]: DualSelectPair) => localPolicies.has(pk)
|
||||
: ([_0, _1, _2, policy]: DualSelectPair<Policy>) => policy !== undefined;
|
||||
}
|
||||
import {
|
||||
policiesProvider,
|
||||
policiesSelector,
|
||||
promptFieldsProvider,
|
||||
promptFieldsSelector,
|
||||
} from "./PromptStageFormHelpers.js";
|
||||
|
||||
@customElement("ak-stage-prompt-form")
|
||||
export class PromptStageForm extends BaseStageForm<PromptStage> {
|
||||
@ -110,7 +66,7 @@ export class PromptStageForm extends BaseStageForm<PromptStage> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${promptFieldsProvider}
|
||||
.selector=${makeFieldSelector(this.instance?.fields)}
|
||||
.selector=${promptFieldsSelector(this.instance?.fields)}
|
||||
available-label="${msg("Available Fields")}"
|
||||
selected-label="${msg("Selected Fields")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
@ -135,7 +91,7 @@ export class PromptStageForm extends BaseStageForm<PromptStage> {
|
||||
>
|
||||
<ak-dual-select-dynamic-selected
|
||||
.provider=${policiesProvider}
|
||||
.selector=${makePoliciesSelector(this.instance?.validationPolicies)}
|
||||
.selector=${policiesSelector(this.instance?.validationPolicies)}
|
||||
available-label="${msg("Available Fields")}"
|
||||
selected-label="${msg("Selected Fields")}"
|
||||
></ak-dual-select-dynamic-selected>
|
||||
|
82
web/src/admin/stages/prompt/PromptStageFormHelpers.ts
Normal file
82
web/src/admin/stages/prompt/PromptStageFormHelpers.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
|
||||
|
||||
import { msg, str } from "@lit/localize";
|
||||
|
||||
import { PoliciesApi, Policy, Prompt, StagesApi } from "@goauthentik/api";
|
||||
|
||||
const promptToSelect = (p: Prompt) => [
|
||||
p.pk,
|
||||
msg(str`${p.name} ("${p.fieldKey}", of type ${p.type})`),
|
||||
p.name,
|
||||
p,
|
||||
];
|
||||
|
||||
export async function promptFieldsProvider(page = 1, search = "") {
|
||||
const prompts = await new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({
|
||||
ordering: "field_name,order",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: prompts.pagination,
|
||||
options: prompts.results.map(promptToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function promptFieldsSelector(instanceFields: string[] | undefined) {
|
||||
if (!instanceFields) {
|
||||
return async (options: DualSelectPair<Prompt>[]) =>
|
||||
options.filter(([_0, _1, _2, prompt]: DualSelectPair<Prompt>) => prompt !== undefined);
|
||||
}
|
||||
return async () => {
|
||||
const stages = new StagesApi(DEFAULT_CONFIG);
|
||||
const prompts = await Promise.allSettled(
|
||||
instanceFields.map((instanceId) =>
|
||||
stages.stagesPromptPromptsRetrieve({ promptUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
return prompts
|
||||
.filter((p) => p.status === "fulfilled")
|
||||
.map((p) => p.value)
|
||||
.map(promptToSelect);
|
||||
};
|
||||
}
|
||||
|
||||
const policyToSelect = (p: Policy) => [p.pk, `${p.name} (${p.verboseName})`, p.name, p];
|
||||
|
||||
export async function policiesProvider(page = 1, search = "") {
|
||||
const policies = await new PoliciesApi(DEFAULT_CONFIG).policiesAllList({
|
||||
ordering: "name",
|
||||
pageSize: 20,
|
||||
search: search.trim(),
|
||||
page,
|
||||
});
|
||||
|
||||
return {
|
||||
pagination: policies.pagination,
|
||||
options: policies.results.map(policyToSelect),
|
||||
};
|
||||
}
|
||||
|
||||
export function policiesSelector(instancePolicies: string[] | undefined) {
|
||||
if (!instancePolicies) {
|
||||
return async (options: DualSelectPair<Policy>[]) =>
|
||||
options.filter(([_0, _1, _2, policy]: DualSelectPair<Policy>) => policy !== undefined);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const policy = new PoliciesApi(DEFAULT_CONFIG);
|
||||
const policies = await Promise.allSettled(
|
||||
instancePolicies.map((instanceId) =>
|
||||
policy.policiesAllRetrieve({ policyUuid: instanceId }),
|
||||
),
|
||||
);
|
||||
return policies
|
||||
.filter((p) => p.status === "fulfilled")
|
||||
.map((p) => p.value)
|
||||
.map(policyToSelect);
|
||||
};
|
||||
}
|
@ -23,7 +23,7 @@ export class AkDualSelectDynamic extends AkDualSelectProvider {
|
||||
* @attr
|
||||
*/
|
||||
@property({ attribute: false })
|
||||
selector: ([key, _]: DualSelectPair) => boolean = ([_key, _]) => false;
|
||||
selector: (_: DualSelectPair[]) => Promise<DualSelectPair[]> = async (_) => Promise.resolve([]);
|
||||
|
||||
private firstUpdateHasRun = false;
|
||||
|
||||
@ -33,9 +33,9 @@ export class AkDualSelectDynamic extends AkDualSelectProvider {
|
||||
// the selected list with the contents derived from the selector.
|
||||
if (!this.firstUpdateHasRun && this.options.length > 0) {
|
||||
this.firstUpdateHasRun = true;
|
||||
this.selected = Array.from(
|
||||
new Set([...this.selected, ...this.options.filter(this.selector)]),
|
||||
);
|
||||
this.selector(this.options).then((selected) => {
|
||||
this.selected = selected;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user