web/admin: migrate FlowStageBinding form to web

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer
2021-03-31 15:33:58 +02:00
parent 0395c84270
commit 25e043afea
8 changed files with 194 additions and 176 deletions

View File

@ -24,10 +24,6 @@ export class AdminURLManager {
return `/administration/stages/${rest}`;
}
static stageBindings(rest: string): string {
return `/administration/stages/bindings/${rest}`;
}
static sources(rest: string): string {
return `/administration/sources/${rest}`;
}

View File

@ -4,6 +4,8 @@ import { AKResponse } from "../../api/Client";
import { Table, TableColumn } from "../../elements/table/Table";
import "../../elements/forms/DeleteForm";
import "../../elements/forms/ModalForm";
import "./StageBindingForm";
import "../../elements/Tabs";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
@ -14,6 +16,7 @@ import { PAGE_SIZE } from "../../constants";
import { FlowsApi, FlowStageBinding, StagesApi } from "authentik-api";
import { DEFAULT_CONFIG } from "../../api/Config";
import { AdminURLManager } from "../../api/legacy";
import { ifDefined } from "lit-html/directives/if-defined";
@customElement("ak-bound-stages-list")
export class BoundStagesList extends Table<FlowStageBinding> {
@ -52,12 +55,19 @@ export class BoundStagesList extends Table<FlowStageBinding> {
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="${AdminURLManager.stageBindings(`${item.pk}/update/`)}">
<ak-spinner-button slot="trigger" class="pf-m-secondary">
<ak-forms-modal>
<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")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
</button>
</ak-forms-modal>
<ak-forms-delete
.obj=${item}
objectLabel=${gettext("Stage binding")}
@ -95,12 +105,19 @@ export class BoundStagesList extends Table<FlowStageBinding> {
${gettext("No stages are currently bound to this flow.")}
</div>
<div slot="primary">
<ak-modal-button href="${AdminURLManager.stageBindings(`create/?target=${this.target}`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Bind Stage")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-forms-modal>
<span slot="submit">
${gettext("Create")}
</span>
<span slot="header">
${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>
</ak-empty-state>`);
}
@ -127,12 +144,19 @@ export class BoundStagesList extends Table<FlowStageBinding> {
}), html`<ak-spinner></ak-spinner>`)}
</ul>
</ak-dropdown>
<ak-modal-button href="${AdminURLManager.stageBindings(`create/?target=${this.target}`)}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Bind Stage")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-forms-modal>
<span slot="submit">
${gettext("Create")}
</span>
<span slot="header">
${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()}
`;
}

View 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>`;
}
}