web/admin: fix misc dual select on different forms (#11203)

* fix prompt stage

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix identification stage

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix OAuth JWKS sources

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix oauth provider default scopes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix outpost form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix webauthn

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix transport form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
# Conflicts:
#	web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts
#	web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts
This commit is contained in:
Jens L
2024-09-04 13:45:41 +02:00
committed by Jens Langhammer
parent 392a2e582e
commit dd75d5f54b
11 changed files with 100 additions and 46 deletions

View File

@ -205,7 +205,7 @@ gen: gen-build gen-client-ts
web-build: web-install ## Build the Authentik UI web-build: web-install ## Build the Authentik UI
cd web && npm run build cd web && npm run build
web: web-lint-fix web-lint web-check-compile web-test ## Automatically fix formatting issues in the Authentik UI source code, lint the code, and compile it web: web-lint-fix web-lint web-check-compile ## Automatically fix formatting issues in the Authentik UI source code, lint the code, and compile it
web-install: ## Install the necessary libraries to build the Authentik UI web-install: ## Install the necessary libraries to build the Authentik UI
cd web && npm ci cd web && npm ci

View File

@ -11,7 +11,10 @@ import {
redirectUriHelp, redirectUriHelp,
subjectModeOptions, subjectModeOptions,
} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm"; } from "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm";
import { oauth2SourcesProvider } from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; import {
makeSourceSelector,
oauth2SourcesProvider,
} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-number-input"; import "@goauthentik/components/ak-number-input";
@ -263,12 +266,12 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
name="jwksSources" name="jwksSources"
.errorMessages=${errors?.jwksSources ?? []} .errorMessages=${errors?.jwksSources ?? []}
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${oauth2SourcesProvider} .provider=${oauth2SourcesProvider}
.selected=${provider?.jwksSources} .selector=${makeSourceSelector(provider?.jwksSources)}
available-label=${msg("Available Sources")} available-label=${msg("Available Sources")}
selected-label=${msg("Selected Sources")} selected-label=${msg("Selected Sources")}
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.",

View File

@ -1,5 +1,8 @@
import "@goauthentik/admin/applications/wizard/ak-wizard-title"; import "@goauthentik/admin/applications/wizard/ak-wizard-title";
import { oauth2SourcesProvider } from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; import {
makeSourceSelector,
oauth2SourcesProvider,
} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js";
import { import {
makeProxyPropertyMappingsSelector, makeProxyPropertyMappingsSelector,
proxyPropertyMappingsProvider, proxyPropertyMappingsProvider,
@ -11,7 +14,6 @@ import "@goauthentik/components/ak-text-input";
import "@goauthentik/components/ak-textarea-input"; import "@goauthentik/components/ak-textarea-input";
import "@goauthentik/components/ak-toggle-group"; import "@goauthentik/components/ak-toggle-group";
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 "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
@ -228,12 +230,12 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
name="jwksSources" name="jwksSources"
.errorMessages=${errors?.jwksSources ?? []} .errorMessages=${errors?.jwksSources ?? []}
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${oauth2SourcesProvider} .provider=${oauth2SourcesProvider}
.selected=${this.instance?.jwksSources} .selector=${makeSourceSelector(this.instance?.jwksSources)}
available-label=${msg("Available Sources")} available-label=${msg("Available Sources")}
selected-label=${msg("Selected Sources")} selected-label=${msg("Selected Sources")}
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.",

View File

@ -1,5 +1,7 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { severityToLabel } from "@goauthentik/common/labels"; 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 "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio"; import "@goauthentik/elements/forms/Radio";
@ -16,6 +18,7 @@ import {
EventsApi, EventsApi,
Group, Group,
NotificationRule, NotificationRule,
NotificationTransport,
PaginatedNotificationTransportList, PaginatedNotificationTransportList,
SeverityEnum, SeverityEnum,
} from "@goauthentik/api"; } from "@goauthentik/api";
@ -34,6 +37,13 @@ async function eventTransportsProvider(page = 1, search = "") {
}; };
} }
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") @customElement("ak-event-rule-form")
export class RuleForm extends ModelForm<NotificationRule, string> { export class RuleForm extends ModelForm<NotificationRule, string> {
eventTransports?: PaginatedNotificationTransportList; eventTransports?: PaginatedNotificationTransportList;
@ -114,12 +124,12 @@ export class RuleForm extends ModelForm<NotificationRule, string> {
?required=${true} ?required=${true}
name="transports" name="transports"
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${eventTransportsProvider} .provider=${eventTransportsProvider}
.selected=${this.instance?.transports} .selector=${makeTransportSelector(this.instance?.transports)}
available-label="${msg("Available Transports")}" available-label="${msg("Available Transports")}"
selected-label="${msg("Selected Transports")}" selected-label="${msg("Selected Transports")}"
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"Select which transports should be used to notify the user. If none are selected, the notification will only be shown in the authentik UI.", "Select which transports should be used to notify the user. If none are selected, the notification will only be shown in the authentik UI.",

View File

@ -3,6 +3,12 @@ import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js";
import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api"; 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 = "") { export async function oauth2PropertyMappingsProvider(page = 1, search = "") {
const propertyMappings = await new PropertymappingsApi( const propertyMappings = await new PropertymappingsApi(
DEFAULT_CONFIG, DEFAULT_CONFIG,
@ -23,6 +29,5 @@ export function makeOAuth2PropertyMappingsSelector(instanceMappings: string[] |
return localMappings return localMappings
? ([pk, _]: DualSelectPair) => localMappings.has(pk) ? ([pk, _]: DualSelectPair) => localMappings.has(pk)
: ([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) => : ([_0, _1, _2, scope]: DualSelectPair<ScopeMapping>) =>
scope?.managed?.startsWith("goauthentik.io/providers/oauth2/scope-") && scope?.managed && defaultScopes.includes(scope?.managed);
scope?.managed !== "goauthentik.io/providers/oauth2/scope-offline_access";
} }

View File

@ -32,7 +32,7 @@ import {
makeOAuth2PropertyMappingsSelector, makeOAuth2PropertyMappingsSelector,
oauth2PropertyMappingsProvider, oauth2PropertyMappingsProvider,
} from "./OAuth2PropertyMappings.js"; } from "./OAuth2PropertyMappings.js";
import { oauth2SourcesProvider } from "./OAuth2Sources.js"; import { makeSourceSelector, oauth2SourcesProvider } from "./OAuth2Sources.js";
export const clientTypeOptions = [ export const clientTypeOptions = [
{ {
@ -52,12 +52,6 @@ export const clientTypeOptions = [
}, },
]; ];
export const defaultScopes = [
"goauthentik.io/providers/oauth2/scope-openid",
"goauthentik.io/providers/oauth2/scope-email",
"goauthentik.io/providers/oauth2/scope-profile",
];
export const subjectModeOptions = [ export const subjectModeOptions = [
{ {
label: msg("Based on the User's hashed ID"), label: msg("Based on the User's hashed ID"),
@ -335,12 +329,12 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
label=${msg("Trusted OIDC Sources")} label=${msg("Trusted OIDC Sources")}
name="jwksSources" name="jwksSources"
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${oauth2SourcesProvider} .provider=${oauth2SourcesProvider}
.selected=${provider?.jwksSources} .selector=${makeSourceSelector(provider?.jwksSources)}
available-label=${msg("Available Sources")} available-label=${msg("Available Sources")}
selected-label=${msg("Selected Sources")} selected-label=${msg("Selected Sources")}
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.",

View File

@ -1,6 +1,7 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
import { SourcesApi } from "@goauthentik/api"; import { OAuthSource, SourcesApi } from "@goauthentik/api";
export async function oauth2SourcesProvider(page = 1, search = "") { export async function oauth2SourcesProvider(page = 1, search = "") {
const oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({ const oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({
@ -19,3 +20,11 @@ export async function oauth2SourcesProvider(page = 1, search = "") {
]), ]),
}; };
} }
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;
}

View File

@ -1,12 +1,14 @@
import "@goauthentik/admin/common/ak-crypto-certificate-search"; import "@goauthentik/admin/common/ak-crypto-certificate-search";
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search"; import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"; import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
import { oauth2SourcesProvider } from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; import {
makeSourceSelector,
oauth2SourcesProvider,
} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils"; import { first } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-toggle-group"; import "@goauthentik/components/ak-toggle-group";
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 "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect"; import "@goauthentik/elements/forms/SearchSelect";
@ -403,12 +405,12 @@ ${this.instance?.skipPathRegex}</textarea
label=${msg("Trusted OIDC Sources")} label=${msg("Trusted OIDC Sources")}
name="jwksSources" name="jwksSources"
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${oauth2SourcesProvider} .provider=${oauth2SourcesProvider}
.selected=${this.instance?.jwksSources} .selector=${makeSourceSelector(this.instance?.jwksSources)}
available-label=${msg("Available Sources")} available-label=${msg("Available Sources")}
selected-label=${msg("Selected Sources")} selected-label=${msg("Selected Sources")}
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.",

View File

@ -2,7 +2,9 @@ import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
import { deviceTypeRestrictionPair } from "@goauthentik/admin/stages/authenticator_webauthn/utils"; import { deviceTypeRestrictionPair } from "@goauthentik/admin/stages/authenticator_webauthn/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/Alert"; 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 "@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/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/Radio"; import "@goauthentik/elements/forms/Radio";
@ -18,6 +20,7 @@ import {
DeviceClassesEnum, DeviceClassesEnum,
NotConfiguredActionEnum, NotConfiguredActionEnum,
PaginatedStageList, PaginatedStageList,
Stage,
StagesApi, StagesApi,
UserVerificationEnum, UserVerificationEnum,
} from "@goauthentik/api"; } from "@goauthentik/api";
@ -36,6 +39,14 @@ async function stagesProvider(page = 1, search = "") {
}; };
} }
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 = "") { async function authenticatorWebauthnDeviceTypesListProvider(page = 1, search = "") {
const devicetypes = await new StagesApi( const devicetypes = await new StagesApi(
DEFAULT_CONFIG, DEFAULT_CONFIG,
@ -205,14 +216,14 @@ export class AuthenticatorValidateStageForm extends BaseStageForm<AuthenticatorV
label=${msg("Configuration stages")} label=${msg("Configuration stages")}
name="configurationStages" name="configurationStages"
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${stagesProvider} .provider=${stagesProvider}
.selected=${Array.from( .selector=${makeStageSelector(
this.instance?.configurationStages ?? [], this.instance?.configurationStages,
)} )}
available-label="${msg("Available Stages")}" available-label="${msg("Available Stages")}"
selected-label="${msg("Selected Stages")}" selected-label="${msg("Selected Stages")}"
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again.", "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again.",

View File

@ -41,7 +41,7 @@ async function sourcesProvider(page = 1, search = "") {
}; };
} }
async function makeSourcesSelector(instanceSources: string[] | undefined) { function makeSourcesSelector(instanceSources: string[] | undefined) {
const localSources = instanceSources ? new Set(instanceSources) : undefined; const localSources = instanceSources ? new Set(instanceSources) : undefined;
return localSources return localSources

View File

@ -2,6 +2,8 @@ import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
import "@goauthentik/admin/stages/prompt/PromptForm"; import "@goauthentik/admin/stages/prompt/PromptForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PFSize } from "@goauthentik/common/enums"; 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/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/ModalForm"; import "@goauthentik/elements/forms/ModalForm";
@ -11,9 +13,9 @@ import { TemplateResult, html, nothing } from "lit";
import { customElement } from "lit/decorators.js"; import { customElement } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import { PoliciesApi, PromptStage, StagesApi } from "@goauthentik/api"; import { PoliciesApi, Policy, Prompt, PromptStage, StagesApi } from "@goauthentik/api";
async function promptsProvider(page = 1, search = "") { async function promptFieldsProvider(page = 1, search = "") {
const prompts = await new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({ const prompts = await new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({
ordering: "field_name", ordering: "field_name",
pageSize: 20, pageSize: 20,
@ -25,11 +27,19 @@ async function promptsProvider(page = 1, search = "") {
pagination: prompts.pagination, pagination: prompts.pagination,
options: prompts.results.map((prompt) => [ options: prompts.results.map((prompt) => [
prompt.pk, prompt.pk,
str`${prompt.name} ("${prompt.fieldKey}", of type ${prompt.type})`, 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 = "") { async function policiesProvider(page = 1, search = "") {
const policies = await new PoliciesApi(DEFAULT_CONFIG).policiesAllList({ const policies = await new PoliciesApi(DEFAULT_CONFIG).policiesAllList({
ordering: "name", ordering: "name",
@ -47,6 +57,14 @@ async function policiesProvider(page = 1, search = "") {
}; };
} }
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;
}
@customElement("ak-stage-prompt-form") @customElement("ak-stage-prompt-form")
export class PromptStageForm extends BaseStageForm<PromptStage> { export class PromptStageForm extends BaseStageForm<PromptStage> {
loadInstance(pk: string): Promise<PromptStage> { loadInstance(pk: string): Promise<PromptStage> {
@ -90,12 +108,12 @@ export class PromptStageForm extends BaseStageForm<PromptStage> {
?required=${true} ?required=${true}
name="fields" name="fields"
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${promptsProvider} .provider=${promptFieldsProvider}
.selected=${this.instance?.fields} .selector=${makeFieldSelector(this.instance?.fields)}
available-label="${msg("Available Fields")}" available-label="${msg("Available Fields")}"
selected-label="${msg("Selected Fields")}" selected-label="${msg("Selected Fields")}"
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
${this.instance ${this.instance
? html`<ak-forms-modal size=${PFSize.XLarge}> ? html`<ak-forms-modal size=${PFSize.XLarge}>
<span slot="submit"> ${msg("Create")} </span> <span slot="submit"> ${msg("Create")} </span>
@ -115,12 +133,12 @@ export class PromptStageForm extends BaseStageForm<PromptStage> {
label=${msg("Validation Policies")} label=${msg("Validation Policies")}
name="validationPolicies" name="validationPolicies"
> >
<ak-dual-select-provider <ak-dual-select-dynamic-selected
.provider=${policiesProvider} .provider=${policiesProvider}
.selected=${this.instance?.validationPolicies} .selector=${makePoliciesSelector(this.instance?.validationPolicies)}
available-label="${msg("Available Fields")}" available-label="${msg("Available Fields")}"
selected-label="${msg("Selected Fields")}" selected-label="${msg("Selected Fields")}"
></ak-dual-select-provider> ></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"Selected policies are executed when the stage is submitted to validate the data.", "Selected policies are executed when the stage is submitted to validate the data.",