web/admin: migrate policybinding form
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
3124b0f39c
commit
e476186cbc
|
@ -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.policies_bindings import PolicyBindingCreateView
|
|
||||||
from authentik.core.models import Application
|
|
||||||
from authentik.policies.forms import PolicyBindingForm
|
|
||||||
|
|
||||||
|
|
||||||
class TestPolicyBindingView(TestCase):
|
|
||||||
"""Generic admin tests"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.factory = RequestFactory()
|
|
||||||
|
|
||||||
def test_without_get_param(self):
|
|
||||||
"""Test PolicyBindingCreateView without get params"""
|
|
||||||
request = self.factory.get("/")
|
|
||||||
view = PolicyBindingCreateView(request=request)
|
|
||||||
self.assertEqual(view.get_initial(), {})
|
|
||||||
|
|
||||||
def test_with_params_invalid(self):
|
|
||||||
"""Test PolicyBindingCreateView with invalid get params"""
|
|
||||||
request = self.factory.get("/", {"target": uuid4()})
|
|
||||||
view = PolicyBindingCreateView(request=request)
|
|
||||||
self.assertEqual(view.get_initial(), {})
|
|
||||||
|
|
||||||
def test_with_params(self):
|
|
||||||
"""Test PolicyBindingCreateView with get params"""
|
|
||||||
target = Application.objects.create(name="test")
|
|
||||||
request = self.factory.get("/", {"target": target.pk.hex})
|
|
||||||
view = PolicyBindingCreateView(request=request)
|
|
||||||
self.assertEqual(view.get_initial(), {"target": target, "order": 0})
|
|
||||||
|
|
||||||
self.assertTrue(
|
|
||||||
isinstance(
|
|
||||||
PolicyBindingForm(initial={"target": "foo"}).fields["target"].widget,
|
|
||||||
forms.HiddenInput,
|
|
||||||
)
|
|
||||||
)
|
|
|
@ -4,7 +4,6 @@ from django.urls import path
|
||||||
from authentik.admin.views import (
|
from authentik.admin.views import (
|
||||||
outposts_service_connections,
|
outposts_service_connections,
|
||||||
policies,
|
policies,
|
||||||
policies_bindings,
|
|
||||||
property_mappings,
|
property_mappings,
|
||||||
providers,
|
providers,
|
||||||
sources,
|
sources,
|
||||||
|
@ -27,17 +26,6 @@ urlpatterns = [
|
||||||
policies.PolicyUpdateView.as_view(),
|
policies.PolicyUpdateView.as_view(),
|
||||||
name="policy-update",
|
name="policy-update",
|
||||||
),
|
),
|
||||||
# Policy bindings
|
|
||||||
path(
|
|
||||||
"policies/bindings/create/",
|
|
||||||
policies_bindings.PolicyBindingCreateView.as_view(),
|
|
||||||
name="policy-binding-create",
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
"policies/bindings/<uuid:pk>/update/",
|
|
||||||
policies_bindings.PolicyBindingUpdateView.as_view(),
|
|
||||||
name="policy-binding-update",
|
|
||||||
),
|
|
||||||
# Providers
|
# Providers
|
||||||
path(
|
path(
|
||||||
"providers/create/",
|
"providers/create/",
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
"""authentik PolicyBinding 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.lib.views import CreateAssignPermView
|
|
||||||
from authentik.policies.forms import PolicyBindingForm
|
|
||||||
from authentik.policies.models import PolicyBinding, PolicyBindingModel
|
|
||||||
|
|
||||||
|
|
||||||
class PolicyBindingCreateView(
|
|
||||||
SuccessMessageMixin,
|
|
||||||
LoginRequiredMixin,
|
|
||||||
DjangoPermissionRequiredMixin,
|
|
||||||
CreateAssignPermView,
|
|
||||||
):
|
|
||||||
"""Create new PolicyBinding"""
|
|
||||||
|
|
||||||
model = PolicyBinding
|
|
||||||
permission_required = "authentik_policies.add_policybinding"
|
|
||||||
form_class = PolicyBindingForm
|
|
||||||
|
|
||||||
template_name = "generic/create.html"
|
|
||||||
success_url = reverse_lazy("authentik_core:if-admin")
|
|
||||||
success_message = _("Successfully created PolicyBinding")
|
|
||||||
|
|
||||||
def get_initial(self) -> dict[str, Any]:
|
|
||||||
if "target" in self.request.GET:
|
|
||||||
initial_target_pk = self.request.GET["target"]
|
|
||||||
targets = PolicyBindingModel.objects.filter(
|
|
||||||
pk=initial_target_pk
|
|
||||||
).select_subclasses()
|
|
||||||
if not targets.exists():
|
|
||||||
return {}
|
|
||||||
max_order = PolicyBinding.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 PolicyBindingUpdateView(
|
|
||||||
SuccessMessageMixin,
|
|
||||||
LoginRequiredMixin,
|
|
||||||
PermissionRequiredMixin,
|
|
||||||
UpdateView,
|
|
||||||
):
|
|
||||||
"""Update policybinding"""
|
|
||||||
|
|
||||||
model = PolicyBinding
|
|
||||||
permission_required = "authentik_policies.change_policybinding"
|
|
||||||
form_class = PolicyBindingForm
|
|
||||||
|
|
||||||
template_name = "generic/update.html"
|
|
||||||
success_url = reverse_lazy("authentik_core:if-admin")
|
|
||||||
success_message = _("Successfully updated PolicyBinding")
|
|
|
@ -29,6 +29,9 @@ def get_attrs(obj: SerializerModel) -> dict[str, Any]:
|
||||||
for to_remove_name in to_remove:
|
for to_remove_name in to_remove:
|
||||||
if to_remove_name in data:
|
if to_remove_name in data:
|
||||||
data.pop(to_remove_name)
|
data.pop(to_remove_name)
|
||||||
|
for key in list(data.keys()):
|
||||||
|
if key.endswith("_obj"):
|
||||||
|
data.pop(key)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class PolicyBindingModelForeignKey(PrimaryKeyRelatedField):
|
||||||
# checks the PK of PolicyBindingModel (for example),
|
# checks the PK of PolicyBindingModel (for example),
|
||||||
# but we get given the Primary Key of the inheriting class
|
# but we get given the Primary Key of the inheriting class
|
||||||
for model in self.get_queryset().select_subclasses().all():
|
for model in self.get_queryset().select_subclasses().all():
|
||||||
if str(model.pk) == data:
|
if str(model.pk) == str(data):
|
||||||
return model
|
return model
|
||||||
# as a fallback we still try a direct lookup
|
# as a fallback we still try a direct lookup
|
||||||
return self.get_queryset().get_subclass(pk=data)
|
return self.get_queryset().get_subclass(pk=data)
|
||||||
|
@ -82,7 +82,13 @@ class PolicyBindingSerializer(ModelSerializer):
|
||||||
|
|
||||||
def validate(self, data: OrderedDict) -> OrderedDict:
|
def validate(self, data: OrderedDict) -> OrderedDict:
|
||||||
"""Check that either policy, group or user is set."""
|
"""Check that either policy, group or user is set."""
|
||||||
count = sum([bool(data["policy"]), bool(data["group"]), bool(data["user"])])
|
count = sum(
|
||||||
|
[
|
||||||
|
bool(data.get("policy", None)),
|
||||||
|
bool(data.get("group", None)),
|
||||||
|
bool(data.get("user", None)),
|
||||||
|
]
|
||||||
|
)
|
||||||
invalid = count > 1
|
invalid = count > 1
|
||||||
empty = count < 1
|
empty = count < 1
|
||||||
if invalid:
|
if invalid:
|
||||||
|
|
|
@ -4,10 +4,6 @@ export class AdminURLManager {
|
||||||
return `/administration/policies/${rest}`;
|
return `/administration/policies/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static policyBindings(rest: string): string {
|
|
||||||
return `/administration/policies/bindings/${rest}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static providers(rest: string): string {
|
static providers(rest: string): string {
|
||||||
return `/administration/providers/${rest}`;
|
return `/administration/providers/${rest}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ import { AdminURLManager } from "../../api/legacy";
|
||||||
|
|
||||||
import "../../elements/forms/ModalForm";
|
import "../../elements/forms/ModalForm";
|
||||||
import "../groups/GroupForm";
|
import "../groups/GroupForm";
|
||||||
|
import "../users/UserForm";
|
||||||
|
import "./PolicyBindingForm";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
|
||||||
@customElement("ak-bound-policies-list")
|
@customElement("ak-bound-policies-list")
|
||||||
export class BoundPoliciesList extends Table<PolicyBinding> {
|
export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
|
@ -43,11 +46,11 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
|
|
||||||
getPolicyUserGroupRow(item: PolicyBinding): string {
|
getPolicyUserGroupRow(item: PolicyBinding): string {
|
||||||
if (item.policy) {
|
if (item.policy) {
|
||||||
return gettext(`Policy ${item.policy.name}`);
|
return gettext(`Policy ${item.policyObj?.name}`);
|
||||||
} else if (item.group) {
|
} else if (item.group) {
|
||||||
return gettext(`Group ${item.group.name}`);
|
return gettext(`Group ${item.groupObj?.name}`);
|
||||||
} else if (item.user) {
|
} else if (item.user) {
|
||||||
return gettext(`User ${item.user.name}`);
|
return gettext(`User ${item.userObj?.name}`);
|
||||||
} else {
|
} else {
|
||||||
return gettext("");
|
return gettext("");
|
||||||
}
|
}
|
||||||
|
@ -55,7 +58,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
|
|
||||||
getObjectEditButton(item: PolicyBinding): TemplateResult {
|
getObjectEditButton(item: PolicyBinding): TemplateResult {
|
||||||
if (item.policy) {
|
if (item.policy) {
|
||||||
return html`<ak-modal-button href="${AdminURLManager.policies(`${item.policy?.policyUuid}/update/`)}">
|
return html`<ak-modal-button href="${AdminURLManager.policies(`${item.policy}/update/`)}">
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
||||||
${gettext("Edit Policy")}
|
${gettext("Edit Policy")}
|
||||||
</ak-spinner-button>
|
</ak-spinner-button>
|
||||||
|
@ -69,19 +72,26 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
<span slot="header">
|
<span slot="header">
|
||||||
${gettext("Update Group")}
|
${gettext("Update Group")}
|
||||||
</span>
|
</span>
|
||||||
<ak-group-form slot="form" .group=${item.group}>
|
<ak-group-form slot="form" .group=${item.groupObj}>
|
||||||
</ak-group-form>
|
</ak-group-form>
|
||||||
<button slot="trigger" class="pf-c-button pf-m-primary">
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
${gettext("Edit Group")}
|
${gettext("Edit Group")}
|
||||||
</button>
|
</button>
|
||||||
</ak-forms-modal>`;
|
</ak-forms-modal>`;
|
||||||
} else if (item.user) {
|
} else if (item.user) {
|
||||||
return html`<ak-modal-button href="${AdminURLManager.policies(`${item.user?.id}/update/`)}">
|
return html`<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-secondary">
|
<span slot="submit">
|
||||||
${gettext("Edit User")}
|
${gettext("Update")}
|
||||||
</ak-spinner-button>
|
</span>
|
||||||
<div slot="modal"></div>
|
<span slot="header">
|
||||||
</ak-modal-button>`;
|
${gettext("Update User")}
|
||||||
|
</span>
|
||||||
|
<ak-user-form slot="form" .user=${item.userObj}>
|
||||||
|
</ak-user-form>
|
||||||
|
<button slot="trigger" class="pf-m-secondary pf-c-button">
|
||||||
|
${gettext("Edit")}
|
||||||
|
</button>
|
||||||
|
</ak-forms-modal>`;
|
||||||
} else {
|
} else {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
@ -95,12 +105,19 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
html`${item.timeout}`,
|
html`${item.timeout}`,
|
||||||
html`
|
html`
|
||||||
${this.getObjectEditButton(item)}
|
${this.getObjectEditButton(item)}
|
||||||
<ak-modal-button href="${AdminURLManager.policyBindings(`${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 Binding")}
|
||||||
|
</span>
|
||||||
|
<ak-policy-binding-form slot="form" .binding=${item} targetPk=${ifDefined(this.target)}>
|
||||||
|
</ak-policy-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("Policy binding")}
|
objectLabel=${gettext("Policy binding")}
|
||||||
|
@ -122,12 +139,19 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
${gettext("No policies are currently bound to this object.")}
|
${gettext("No policies are currently bound to this object.")}
|
||||||
</div>
|
</div>
|
||||||
<div slot="primary">
|
<div slot="primary">
|
||||||
<ak-modal-button href=${AdminURLManager.policyBindings(`create/?target=${this.target}`)}>
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
<span slot="submit">
|
||||||
${gettext("Bind Policy")}
|
${gettext("Create")}
|
||||||
</ak-spinner-button>
|
</span>
|
||||||
<div slot="modal"></div>
|
<span slot="header">
|
||||||
</ak-modal-button>
|
${gettext("Create Binding")}
|
||||||
|
</span>
|
||||||
|
<ak-policy-binding-form slot="form" targetPk=${ifDefined(this.target)}>
|
||||||
|
</ak-policy-binding-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
|
${gettext("Create Binding")}
|
||||||
|
</button>
|
||||||
|
</ak-forms-modal>
|
||||||
</div>
|
</div>
|
||||||
</ak-empty-state>`);
|
</ak-empty-state>`);
|
||||||
}
|
}
|
||||||
|
@ -154,12 +178,19 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
|
||||||
}), html`<ak-spinner></ak-spinner>`)}
|
}), html`<ak-spinner></ak-spinner>`)}
|
||||||
</ul>
|
</ul>
|
||||||
</ak-dropdown>
|
</ak-dropdown>
|
||||||
<ak-modal-button href=${AdminURLManager.policyBindings(`create/?target=${this.target}`)}>
|
<ak-forms-modal>
|
||||||
<ak-spinner-button slot="trigger" class="pf-m-primary">
|
<span slot="submit">
|
||||||
${gettext("Bind Policy")}
|
${gettext("Create")}
|
||||||
</ak-spinner-button>
|
</span>
|
||||||
<div slot="modal"></div>
|
<span slot="header">
|
||||||
</ak-modal-button>
|
${gettext("Create Binding")}
|
||||||
|
</span>
|
||||||
|
<ak-policy-binding-form slot="form" targetPk=${ifDefined(this.target)}>
|
||||||
|
</ak-policy-binding-form>
|
||||||
|
<button slot="trigger" class="pf-c-button pf-m-primary">
|
||||||
|
${gettext("Create Binding")}
|
||||||
|
</button>
|
||||||
|
</ak-forms-modal>
|
||||||
${super.renderToolbar()}
|
${super.renderToolbar()}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
138
web/src/pages/policies/PolicyBindingForm.ts
Normal file
138
web/src/pages/policies/PolicyBindingForm.ts
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
import { CoreApi, PoliciesApi, Policy, PolicyBinding } 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 { groupBy } from "../../utils";
|
||||||
|
import "../../elements/forms/HorizontalFormElement";
|
||||||
|
|
||||||
|
@customElement("ak-policy-binding-form")
|
||||||
|
export class PolicyBindingForm extends Form<PolicyBinding> {
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
binding?: PolicyBinding;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
targetPk?: string;
|
||||||
|
|
||||||
|
getSuccessMessage(): string {
|
||||||
|
if (this.binding) {
|
||||||
|
return gettext("Successfully updated binding.");
|
||||||
|
} else {
|
||||||
|
return gettext("Successfully created binding.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async customValidate(form: PolicyBinding): Promise<PolicyBinding> {
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (data: PolicyBinding): Promise<PolicyBinding> => {
|
||||||
|
if (this.binding) {
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsUpdate({
|
||||||
|
policyBindingUuid: this.binding.pk || "",
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsCreate({
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
groupPolicies(policies: Policy[]): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${groupBy<Policy>(policies, (p => p.verboseName || "")).map(([group, policies]) => {
|
||||||
|
return html`<optgroup label=${group}>
|
||||||
|
${policies.map(p => {
|
||||||
|
const selected = (this.binding?.policy === p.pk);
|
||||||
|
return html`<option ?selected=${selected} value=${ifDefined(p.pk)}>${p.name}</option>`;
|
||||||
|
})}
|
||||||
|
</optgroup>`;
|
||||||
|
})}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getOrder(): Promise<number> {
|
||||||
|
if (this.binding) {
|
||||||
|
return Promise.resolve(this.binding.order);
|
||||||
|
}
|
||||||
|
return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsList({
|
||||||
|
target: this.targetPk || "",
|
||||||
|
}).then(bindings => {
|
||||||
|
const orders = bindings.results.map(binding => binding.order);
|
||||||
|
return Math.max(...orders) + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
renderForm(): TemplateResult {
|
||||||
|
return html`<form class="pf-c-form pf-m-horizontal">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Policy")}
|
||||||
|
name="policy">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="" ?selected=${this.binding?.policy === undefined}>---------</option>
|
||||||
|
${until(new PoliciesApi(DEFAULT_CONFIG).policiesAllList({
|
||||||
|
ordering: "pk"
|
||||||
|
}).then(policies => {
|
||||||
|
return this.groupPolicies(policies.results);
|
||||||
|
}), html``)}
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Group")}
|
||||||
|
name="group">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="" ?selected=${this.binding?.group === undefined}>---------</option>
|
||||||
|
${until(new CoreApi(DEFAULT_CONFIG).coreGroupsList({
|
||||||
|
ordering: "pk"
|
||||||
|
}).then(groups => {
|
||||||
|
return groups.results.map(group => {
|
||||||
|
return html`<option value=${ifDefined(group.pk)} ?selected=${group.pk === this.binding?.group}>${group.name}</option>`;
|
||||||
|
});
|
||||||
|
}), html``)}
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("User")}
|
||||||
|
name="user">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option value="" ?selected=${this.binding?.user === undefined}>---------</option>
|
||||||
|
${until(new CoreApi(DEFAULT_CONFIG).coreUsersList({
|
||||||
|
ordering: "pk"
|
||||||
|
}).then(users => {
|
||||||
|
return users.results.map(user => {
|
||||||
|
return html`<option value=${ifDefined(user.pk)} ?selected=${user.pk === this.binding?.user}>${user.name}</option>`;
|
||||||
|
});
|
||||||
|
}), html``)}
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<input required name="target" type="hidden" value=${ifDefined(this.binding?.target || this.targetPk)}>
|
||||||
|
<ak-form-element-horizontal name="enabled">
|
||||||
|
<div class="pf-c-check">
|
||||||
|
<input type="checkbox" class="pf-c-check__input" ?checked=${this.binding?.enabled || true}>
|
||||||
|
<label class="pf-c-check__label">
|
||||||
|
${gettext("Enabled")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Order")}
|
||||||
|
?required=${true}
|
||||||
|
name="order">
|
||||||
|
<input type="number" value="${until(this.getOrder(), this.binding?.order)}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${gettext("Timeout")}
|
||||||
|
?required=${true}
|
||||||
|
name="timeout">
|
||||||
|
<input type="number" value="${this.binding?.timeout || 30}" class="pf-c-form-control" required>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
</form>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in a new issue