web/admin: migrate FlowStageBinding form to web
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		| @ -1,43 +0,0 @@ | |||||||
| """admin tests""" |  | ||||||
| from uuid import uuid4 |  | ||||||
|  |  | ||||||
| from django import forms |  | ||||||
| from django.test import TestCase |  | ||||||
| from django.test.client import RequestFactory |  | ||||||
|  |  | ||||||
| from authentik.admin.views.stages_bindings import StageBindingCreateView |  | ||||||
| from authentik.flows.forms import FlowStageBindingForm |  | ||||||
| from authentik.flows.models import Flow |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestStageBindingView(TestCase): |  | ||||||
|     """Generic admin tests""" |  | ||||||
|  |  | ||||||
|     def setUp(self): |  | ||||||
|         self.factory = RequestFactory() |  | ||||||
|  |  | ||||||
|     def test_without_get_param(self): |  | ||||||
|         """Test StageBindingCreateView without get params""" |  | ||||||
|         request = self.factory.get("/") |  | ||||||
|         view = StageBindingCreateView(request=request) |  | ||||||
|         self.assertEqual(view.get_initial(), {}) |  | ||||||
|  |  | ||||||
|     def test_with_params_invalid(self): |  | ||||||
|         """Test StageBindingCreateView with invalid get params""" |  | ||||||
|         request = self.factory.get("/", {"target": uuid4()}) |  | ||||||
|         view = StageBindingCreateView(request=request) |  | ||||||
|         self.assertEqual(view.get_initial(), {}) |  | ||||||
|  |  | ||||||
|     def test_with_params(self): |  | ||||||
|         """Test StageBindingCreateView with get params""" |  | ||||||
|         target = Flow.objects.create(name="test", slug="test") |  | ||||||
|         request = self.factory.get("/", {"target": target.pk.hex}) |  | ||||||
|         view = StageBindingCreateView(request=request) |  | ||||||
|         self.assertEqual(view.get_initial(), {"target": target, "order": 0}) |  | ||||||
|  |  | ||||||
|         self.assertTrue( |  | ||||||
|             isinstance( |  | ||||||
|                 FlowStageBindingForm(initial={"target": "foo"}).fields["target"].widget, |  | ||||||
|                 forms.HiddenInput, |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
| @ -9,7 +9,6 @@ from authentik.admin.views import ( | |||||||
|     providers, |     providers, | ||||||
|     sources, |     sources, | ||||||
|     stages, |     stages, | ||||||
|     stages_bindings, |  | ||||||
| ) | ) | ||||||
| from authentik.providers.saml.views.metadata import MetadataImportView | from authentik.providers.saml.views.metadata import MetadataImportView | ||||||
|  |  | ||||||
| @ -62,17 +61,6 @@ urlpatterns = [ | |||||||
|         stages.StageUpdateView.as_view(), |         stages.StageUpdateView.as_view(), | ||||||
|         name="stage-update", |         name="stage-update", | ||||||
|     ), |     ), | ||||||
|     # Stage bindings |  | ||||||
|     path( |  | ||||||
|         "stages/bindings/create/", |  | ||||||
|         stages_bindings.StageBindingCreateView.as_view(), |  | ||||||
|         name="stage-binding-create", |  | ||||||
|     ), |  | ||||||
|     path( |  | ||||||
|         "stages/bindings/<uuid:pk>/update/", |  | ||||||
|         stages_bindings.StageBindingUpdateView.as_view(), |  | ||||||
|         name="stage-binding-update", |  | ||||||
|     ), |  | ||||||
|     # Property Mappings |     # Property Mappings | ||||||
|     path( |     path( | ||||||
|         "property-mappings/create/", |         "property-mappings/create/", | ||||||
|  | |||||||
| @ -1,65 +0,0 @@ | |||||||
| """authentik StageBinding administration""" |  | ||||||
| from typing import Any |  | ||||||
|  |  | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin |  | ||||||
| from django.contrib.auth.mixins import ( |  | ||||||
|     PermissionRequiredMixin as DjangoPermissionRequiredMixin, |  | ||||||
| ) |  | ||||||
| from django.contrib.messages.views import SuccessMessageMixin |  | ||||||
| from django.db.models import Max |  | ||||||
| from django.urls import reverse_lazy |  | ||||||
| from django.utils.translation import gettext as _ |  | ||||||
| from django.views.generic import UpdateView |  | ||||||
| from guardian.mixins import PermissionRequiredMixin |  | ||||||
|  |  | ||||||
| from authentik.flows.forms import FlowStageBindingForm |  | ||||||
| from authentik.flows.models import Flow, FlowStageBinding |  | ||||||
| from authentik.lib.views import CreateAssignPermView |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class StageBindingCreateView( |  | ||||||
|     SuccessMessageMixin, |  | ||||||
|     LoginRequiredMixin, |  | ||||||
|     DjangoPermissionRequiredMixin, |  | ||||||
|     CreateAssignPermView, |  | ||||||
| ): |  | ||||||
|     """Create new StageBinding""" |  | ||||||
|  |  | ||||||
|     model = FlowStageBinding |  | ||||||
|     permission_required = "authentik_flows.add_flowstagebinding" |  | ||||||
|     form_class = FlowStageBindingForm |  | ||||||
|  |  | ||||||
|     template_name = "generic/create.html" |  | ||||||
|     success_url = reverse_lazy("authentik_core:if-admin") |  | ||||||
|     success_message = _("Successfully created StageBinding") |  | ||||||
|  |  | ||||||
|     def get_initial(self) -> dict[str, Any]: |  | ||||||
|         if "target" in self.request.GET: |  | ||||||
|             initial_target_pk = self.request.GET["target"] |  | ||||||
|             targets = Flow.objects.filter(pk=initial_target_pk).select_subclasses() |  | ||||||
|             if not targets.exists(): |  | ||||||
|                 return {} |  | ||||||
|             max_order = FlowStageBinding.objects.filter( |  | ||||||
|                 target=targets.first() |  | ||||||
|             ).aggregate(Max("order"))["order__max"] |  | ||||||
|             if not isinstance(max_order, int): |  | ||||||
|                 max_order = -1 |  | ||||||
|             return {"target": targets.first(), "order": max_order + 1} |  | ||||||
|         return super().get_initial() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class StageBindingUpdateView( |  | ||||||
|     SuccessMessageMixin, |  | ||||||
|     LoginRequiredMixin, |  | ||||||
|     PermissionRequiredMixin, |  | ||||||
|     UpdateView, |  | ||||||
| ): |  | ||||||
|     """Update FlowStageBinding""" |  | ||||||
|  |  | ||||||
|     model = FlowStageBinding |  | ||||||
|     permission_required = "authentik_flows.change_flowstagebinding" |  | ||||||
|     form_class = FlowStageBindingForm |  | ||||||
|  |  | ||||||
|     template_name = "generic/update.html" |  | ||||||
|     success_url = reverse_lazy("authentik_core:if-admin") |  | ||||||
|     success_message = _("Successfully updated StageBinding") |  | ||||||
| @ -1,34 +0,0 @@ | |||||||
| """Flow and Stage forms""" |  | ||||||
| from django import forms |  | ||||||
|  |  | ||||||
| from authentik.flows.models import FlowStageBinding, Stage |  | ||||||
| from authentik.lib.widgets import GroupedModelChoiceField |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class FlowStageBindingForm(forms.ModelForm): |  | ||||||
|     """FlowStageBinding Form""" |  | ||||||
|  |  | ||||||
|     stage = GroupedModelChoiceField( |  | ||||||
|         queryset=Stage.objects.all().order_by("name").select_subclasses(), |  | ||||||
|         to_field_name="stage_uuid", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     def __init__(self, *args, **kwargs): |  | ||||||
|         super().__init__(*args, **kwargs) |  | ||||||
|         if "target" in self.initial: |  | ||||||
|             self.fields["target"].widget = forms.HiddenInput() |  | ||||||
|  |  | ||||||
|     class Meta: |  | ||||||
|  |  | ||||||
|         model = FlowStageBinding |  | ||||||
|         fields = [ |  | ||||||
|             "target", |  | ||||||
|             "stage", |  | ||||||
|             "evaluate_on_plan", |  | ||||||
|             "re_evaluate_policies", |  | ||||||
|             "order", |  | ||||||
|             "policy_engine_mode", |  | ||||||
|         ] |  | ||||||
|         widgets = { |  | ||||||
|             "name": forms.TextInput(), |  | ||||||
|         } |  | ||||||
| @ -12,8 +12,8 @@ from rest_framework.fields import ( | |||||||
|     DateField, |     DateField, | ||||||
|     DateTimeField, |     DateTimeField, | ||||||
|     EmailField, |     EmailField, | ||||||
|  |     HiddenField, | ||||||
|     IntegerField, |     IntegerField, | ||||||
|     HiddenField |  | ||||||
| ) | ) | ||||||
| from rest_framework.serializers import BaseSerializer | from rest_framework.serializers import BaseSerializer | ||||||
|  |  | ||||||
|  | |||||||
| @ -24,10 +24,6 @@ export class AdminURLManager { | |||||||
|         return `/administration/stages/${rest}`; |         return `/administration/stages/${rest}`; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static stageBindings(rest: string): string { |  | ||||||
|         return `/administration/stages/bindings/${rest}`; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static sources(rest: string): string { |     static sources(rest: string): string { | ||||||
|         return `/administration/sources/${rest}`; |         return `/administration/sources/${rest}`; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ import { AKResponse } from "../../api/Client"; | |||||||
| import { Table, TableColumn } from "../../elements/table/Table"; | import { Table, TableColumn } from "../../elements/table/Table"; | ||||||
|  |  | ||||||
| import "../../elements/forms/DeleteForm"; | import "../../elements/forms/DeleteForm"; | ||||||
|  | import "../../elements/forms/ModalForm"; | ||||||
|  | import "./StageBindingForm"; | ||||||
| import "../../elements/Tabs"; | import "../../elements/Tabs"; | ||||||
| import "../../elements/buttons/ModalButton"; | import "../../elements/buttons/ModalButton"; | ||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../elements/buttons/SpinnerButton"; | ||||||
| @ -14,6 +16,7 @@ import { PAGE_SIZE } from "../../constants"; | |||||||
| import { FlowsApi, FlowStageBinding, StagesApi } from "authentik-api"; | import { FlowsApi, FlowStageBinding, StagesApi } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../api/Config"; | ||||||
| import { AdminURLManager } from "../../api/legacy"; | import { AdminURLManager } from "../../api/legacy"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  |  | ||||||
| @customElement("ak-bound-stages-list") | @customElement("ak-bound-stages-list") | ||||||
| export class BoundStagesList extends Table<FlowStageBinding> { | export class BoundStagesList extends Table<FlowStageBinding> { | ||||||
| @ -52,12 +55,19 @@ export class BoundStagesList extends Table<FlowStageBinding> { | |||||||
|                 </ak-spinner-button> |                 </ak-spinner-button> | ||||||
|                 <div slot="modal"></div> |                 <div slot="modal"></div> | ||||||
|             </ak-modal-button> |             </ak-modal-button> | ||||||
|             <ak-modal-button href="${AdminURLManager.stageBindings(`${item.pk}/update/`)}"> |             <ak-forms-modal> | ||||||
|                 <ak-spinner-button slot="trigger" class="pf-m-secondary"> |                 <span slot="submit"> | ||||||
|  |                     ${gettext("Update")} | ||||||
|  |                 </span> | ||||||
|  |                 <span slot="header"> | ||||||
|  |                     ${gettext("Update Stage binding")} | ||||||
|  |                 </span> | ||||||
|  |                 <ak-stage-binding-form slot="form" .fsb=${item}> | ||||||
|  |                 </ak-stage-binding-form> | ||||||
|  |                 <button slot="trigger" class="pf-c-button pf-m-secondary"> | ||||||
|                     ${gettext("Edit Binding")} |                     ${gettext("Edit Binding")} | ||||||
|                 </ak-spinner-button> |                 </button> | ||||||
|                 <div slot="modal"></div> |             </ak-forms-modal> | ||||||
|             </ak-modal-button> |  | ||||||
|             <ak-forms-delete |             <ak-forms-delete | ||||||
|                 .obj=${item} |                 .obj=${item} | ||||||
|                 objectLabel=${gettext("Stage binding")} |                 objectLabel=${gettext("Stage binding")} | ||||||
| @ -95,12 +105,19 @@ export class BoundStagesList extends Table<FlowStageBinding> { | |||||||
|                 ${gettext("No stages are currently bound to this flow.")} |                 ${gettext("No stages are currently bound to this flow.")} | ||||||
|             </div> |             </div> | ||||||
|             <div slot="primary"> |             <div slot="primary"> | ||||||
|                 <ak-modal-button href="${AdminURLManager.stageBindings(`create/?target=${this.target}`)}"> |                 <ak-forms-modal> | ||||||
|                     <ak-spinner-button slot="trigger" class="pf-m-primary"> |                     <span slot="submit"> | ||||||
|                         ${gettext("Bind Stage")} |                         ${gettext("Create")} | ||||||
|                     </ak-spinner-button> |                     </span> | ||||||
|                     <div slot="modal"></div> |                     <span slot="header"> | ||||||
|                 </ak-modal-button> |                         ${gettext("Create Stage binding")} | ||||||
|  |                     </span> | ||||||
|  |                     <ak-stage-binding-form slot="form" targetPk=${ifDefined(this.target)}> | ||||||
|  |                     </ak-stage-binding-form> | ||||||
|  |                     <button slot="trigger" class="pf-c-button pf-m-primary"> | ||||||
|  |                         ${gettext("Bind stage")} | ||||||
|  |                     </button> | ||||||
|  |                 </ak-forms-modal> | ||||||
|             </div> |             </div> | ||||||
|         </ak-empty-state>`); |         </ak-empty-state>`); | ||||||
|     } |     } | ||||||
| @ -127,12 +144,19 @@ export class BoundStagesList extends Table<FlowStageBinding> { | |||||||
|                 }), html`<ak-spinner></ak-spinner>`)} |                 }), html`<ak-spinner></ak-spinner>`)} | ||||||
|             </ul> |             </ul> | ||||||
|         </ak-dropdown> |         </ak-dropdown> | ||||||
|         <ak-modal-button href="${AdminURLManager.stageBindings(`create/?target=${this.target}`)}"> |         <ak-forms-modal> | ||||||
|             <ak-spinner-button slot="trigger" class="pf-m-primary"> |             <span slot="submit"> | ||||||
|                 ${gettext("Bind Stage")} |                 ${gettext("Create")} | ||||||
|             </ak-spinner-button> |             </span> | ||||||
|             <div slot="modal"></div> |             <span slot="header"> | ||||||
|         </ak-modal-button> |                 ${gettext("Create Stage binding")} | ||||||
|  |             </span> | ||||||
|  |             <ak-stage-binding-form slot="form" targetPk=${ifDefined(this.target)}> | ||||||
|  |             </ak-stage-binding-form> | ||||||
|  |             <button slot="trigger" class="pf-c-button pf-m-secondary"> | ||||||
|  |                 ${gettext("Bind stage")} | ||||||
|  |             </button> | ||||||
|  |         </ak-forms-modal> | ||||||
|         ${super.renderToolbar()} |         ${super.renderToolbar()} | ||||||
|         `; |         `; | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										152
									
								
								web/src/pages/flows/StageBindingForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								web/src/pages/flows/StageBindingForm.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | |||||||
|  | import { FlowsApi, FlowStageBinding, FlowStageBindingPolicyEngineModeEnum, Stage, StagesApi } from "authentik-api"; | ||||||
|  | import { gettext } from "django"; | ||||||
|  | import { customElement, property } from "lit-element"; | ||||||
|  | import { html, TemplateResult } from "lit-html"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../api/Config"; | ||||||
|  | import { Form } from "../../elements/forms/Form"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import "../../elements/forms/HorizontalFormElement"; | ||||||
|  |  | ||||||
|  | @customElement("ak-stage-binding-form") | ||||||
|  | export class StageBindingForm extends Form<FlowStageBinding> { | ||||||
|  |  | ||||||
|  |     @property({attribute: false}) | ||||||
|  |     fsb?: FlowStageBinding; | ||||||
|  |  | ||||||
|  |     @property() | ||||||
|  |     targetPk?: string; | ||||||
|  |  | ||||||
|  |     getSuccessMessage(): string { | ||||||
|  |         if (this.fsb) { | ||||||
|  |             return gettext("Successfully updated binding."); | ||||||
|  |         } else { | ||||||
|  |             return gettext("Successfully created binding."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send = (data: FlowStageBinding): Promise<FlowStageBinding> => { | ||||||
|  |         if (this.fsb) { | ||||||
|  |             return new FlowsApi(DEFAULT_CONFIG).flowsBindingsUpdate({ | ||||||
|  |                 fsbUuid: this.fsb.pk || "", | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             return new FlowsApi(DEFAULT_CONFIG).flowsBindingsCreate({ | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     groupStages(stages: Stage[]): TemplateResult { | ||||||
|  |         const m = new Map<string, Stage[]>(); | ||||||
|  |         stages.forEach(p => { | ||||||
|  |             if (!m.has(p.verboseName || "")) { | ||||||
|  |                 m.set(p.verboseName || "", []); | ||||||
|  |             } | ||||||
|  |             const tProviders = m.get(p.verboseName || "") || []; | ||||||
|  |             tProviders.push(p); | ||||||
|  |         }); | ||||||
|  |         return html` | ||||||
|  |             ${Array.from(m).map(([group, stages]) => { | ||||||
|  |                 return html`<optgroup label=${group}> | ||||||
|  |                     ${stages.map(stage => { | ||||||
|  |                         const selected = (this.fsb?.stage === stage.pk); | ||||||
|  |                         return html`<option ?selected=${selected} value=${ifDefined(stage.pk)}>${stage.name}</option>`; | ||||||
|  |                     })} | ||||||
|  |                 </optgroup>`; | ||||||
|  |             })} | ||||||
|  |         `; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getOrder(): Promise<number> { | ||||||
|  |         if (this.fsb) { | ||||||
|  |             return Promise.resolve(this.fsb.order); | ||||||
|  |         } | ||||||
|  |         return new FlowsApi(DEFAULT_CONFIG).flowsBindingsList({ | ||||||
|  |             target: this.targetPk || "", | ||||||
|  |         }).then(bindings => { | ||||||
|  |             const orders = bindings.results.map(binding => binding.order); | ||||||
|  |             return Math.max(...orders) + 1; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderTarget(): TemplateResult { | ||||||
|  |         if (this.fsb?.target || this.targetPk) { | ||||||
|  |             return html` | ||||||
|  |             <input required name="target" type="hidden" value=${ifDefined(this.fsb?.target || this.targetPk)}> | ||||||
|  |             `; | ||||||
|  |         } | ||||||
|  |         return html`<ak-form-element-horizontal | ||||||
|  |             label=${gettext("Target")} | ||||||
|  |             ?required=${true} | ||||||
|  |             name="target"> | ||||||
|  |             <select class="pf-c-form-control"> | ||||||
|  |                 ${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({ | ||||||
|  |                     ordering: "pk" | ||||||
|  |                 }).then(flows => { | ||||||
|  |                     return flows.results.map(flow => { | ||||||
|  |                         // No ?selected check here, as this input isnt shown on update forms | ||||||
|  |                         return html`<option value=${ifDefined(flow.pk)}>${flow.name}</option>`; | ||||||
|  |                     }); | ||||||
|  |                 }), html``)} | ||||||
|  |             </select> | ||||||
|  |         </ak-form-element-horizontal>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderForm(): TemplateResult { | ||||||
|  |         return html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|  |             ${this.renderTarget()} | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Stage")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="stage"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     ${until(new StagesApi(DEFAULT_CONFIG).stagesAllList({ | ||||||
|  |                         ordering: "pk" | ||||||
|  |                     }).then(stages => { | ||||||
|  |                         return this.groupStages(stages.results); | ||||||
|  |                     }), html``)} | ||||||
|  |                 </select> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal name="evaluateOnPlan"> | ||||||
|  |                 <div class="pf-c-check"> | ||||||
|  |                     <input type="checkbox" class="pf-c-check__input" ?checked=${this.fsb?.evaluateOnPlan || true}> | ||||||
|  |                     <label class="pf-c-check__label"> | ||||||
|  |                         ${gettext("Evaluate on plan")} | ||||||
|  |                     </label> | ||||||
|  |                 </div> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Evaluate policies during the Flow planning process. Disable this for input-based policies.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal name="reEvaluatePolicies"> | ||||||
|  |                 <div class="pf-c-check"> | ||||||
|  |                     <input type="checkbox" class="pf-c-check__input" ?checked=${this.fsb?.reEvaluatePolicies || false}> | ||||||
|  |                     <label class="pf-c-check__label"> | ||||||
|  |                         ${gettext("Re-evaluate policies")} | ||||||
|  |                     </label> | ||||||
|  |                 </div> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Evaluate policies when the Stage is present to the user.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Order")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="order"> | ||||||
|  |                 <input type="text" value="${until(this.getOrder(), this.fsb?.order)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Policy engine mode")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="policyEngineMode"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value=${FlowStageBindingPolicyEngineModeEnum.Any} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.Any}> | ||||||
|  |                         ${gettext("ANY, any policy must match to grant access.")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${FlowStageBindingPolicyEngineModeEnum.All} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.All}> | ||||||
|  |                         ${gettext("ALL, all policies must match to grant access.")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |         </form>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer