web/admin: migrate application form to web
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		| @ -2,7 +2,6 @@ | |||||||
| from django.urls import path | from django.urls import path | ||||||
|  |  | ||||||
| from authentik.admin.views import ( | from authentik.admin.views import ( | ||||||
|     applications, |  | ||||||
|     flows, |     flows, | ||||||
|     outposts, |     outposts, | ||||||
|     outposts_service_connections, |     outposts_service_connections, | ||||||
| @ -19,17 +18,6 @@ from authentik.admin.views import ( | |||||||
| from authentik.providers.saml.views.metadata import MetadataImportView | from authentik.providers.saml.views.metadata import MetadataImportView | ||||||
|  |  | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     # Applications |  | ||||||
|     path( |  | ||||||
|         "applications/create/", |  | ||||||
|         applications.ApplicationCreateView.as_view(), |  | ||||||
|         name="application-create", |  | ||||||
|     ), |  | ||||||
|     path( |  | ||||||
|         "applications/<uuid:pk>/update/", |  | ||||||
|         applications.ApplicationUpdateView.as_view(), |  | ||||||
|         name="application-update", |  | ||||||
|     ), |  | ||||||
|     # Sources |     # Sources | ||||||
|     path("sources/create/", sources.SourceCreateView.as_view(), name="source-create"), |     path("sources/create/", sources.SourceCreateView.as_view(), name="source-create"), | ||||||
|     path( |     path( | ||||||
|  | |||||||
| @ -1,66 +0,0 @@ | |||||||
| """authentik Application 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.utils.translation import gettext as _ |  | ||||||
| from django.views.generic import UpdateView |  | ||||||
| from guardian.mixins import PermissionRequiredMixin |  | ||||||
| from guardian.shortcuts import get_objects_for_user |  | ||||||
|  |  | ||||||
| from authentik.core.forms.applications import ApplicationForm |  | ||||||
| from authentik.core.models import Application |  | ||||||
| from authentik.lib.views import CreateAssignPermView |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ApplicationCreateView( |  | ||||||
|     SuccessMessageMixin, |  | ||||||
|     LoginRequiredMixin, |  | ||||||
|     DjangoPermissionRequiredMixin, |  | ||||||
|     CreateAssignPermView, |  | ||||||
| ): |  | ||||||
|     """Create new Application""" |  | ||||||
|  |  | ||||||
|     model = Application |  | ||||||
|     form_class = ApplicationForm |  | ||||||
|     permission_required = "authentik_core.add_application" |  | ||||||
|  |  | ||||||
|     success_url = "/" |  | ||||||
|     template_name = "generic/create.html" |  | ||||||
|     success_message = _("Successfully created Application") |  | ||||||
|  |  | ||||||
|     def get_initial(self) -> dict[str, Any]: |  | ||||||
|         if "provider" in self.request.GET: |  | ||||||
|             try: |  | ||||||
|                 initial_provider_pk = int(self.request.GET["provider"]) |  | ||||||
|             except ValueError: |  | ||||||
|                 return super().get_initial() |  | ||||||
|             providers = ( |  | ||||||
|                 get_objects_for_user(self.request.user, "authentik_core.view_provider") |  | ||||||
|                 .filter(pk=initial_provider_pk) |  | ||||||
|                 .select_subclasses() |  | ||||||
|             ) |  | ||||||
|             if not providers.exists(): |  | ||||||
|                 return {} |  | ||||||
|             return {"provider": providers.first()} |  | ||||||
|         return super().get_initial() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ApplicationUpdateView( |  | ||||||
|     SuccessMessageMixin, |  | ||||||
|     LoginRequiredMixin, |  | ||||||
|     PermissionRequiredMixin, |  | ||||||
|     UpdateView, |  | ||||||
| ): |  | ||||||
|     """Update application""" |  | ||||||
|  |  | ||||||
|     model = Application |  | ||||||
|     form_class = ApplicationForm |  | ||||||
|     permission_required = "authentik_core.change_application" |  | ||||||
|  |  | ||||||
|     success_url = "/" |  | ||||||
|     template_name = "generic/update.html" |  | ||||||
|     success_message = _("Successfully updated Application") |  | ||||||
| @ -121,6 +121,7 @@ class ApplicationViewSet(ModelViewSet): | |||||||
|                 required=True, |                 required=True, | ||||||
|             ) |             ) | ||||||
|         ], |         ], | ||||||
|  |         responses={200: "Success"}, | ||||||
|     ) |     ) | ||||||
|     @action(detail=True, methods=["POST"], parser_classes=(MultiPartParser,)) |     @action(detail=True, methods=["POST"], parser_classes=(MultiPartParser,)) | ||||||
|     # pylint: disable=unused-argument |     # pylint: disable=unused-argument | ||||||
| @ -132,12 +133,7 @@ class ApplicationViewSet(ModelViewSet): | |||||||
|             return HttpResponseBadRequest() |             return HttpResponseBadRequest() | ||||||
|         app.meta_icon = icon |         app.meta_icon = icon | ||||||
|         app.save() |         app.save() | ||||||
|         return Response( |         return Response({}) | ||||||
|             get_events_per_1h( |  | ||||||
|                 action=EventAction.AUTHORIZE_APPLICATION, |  | ||||||
|                 context__authorized_application__pk=app.pk.hex, |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     @permission_required( |     @permission_required( | ||||||
|         "authentik_core.view_application", ["authentik_events.view_event"] |         "authentik_core.view_application", ["authentik_events.view_event"] | ||||||
|  | |||||||
| @ -1,50 +0,0 @@ | |||||||
| """authentik Core Application forms""" |  | ||||||
| from django import forms |  | ||||||
| from django.utils.translation import gettext_lazy as _ |  | ||||||
|  |  | ||||||
| from authentik.core.models import Application, Provider |  | ||||||
| from authentik.lib.widgets import GroupedModelChoiceField |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ApplicationForm(forms.ModelForm): |  | ||||||
|     """Application Form""" |  | ||||||
|  |  | ||||||
|     def __init__(self, *args, **kwargs):  # pragma: no cover |  | ||||||
|         super().__init__(*args, **kwargs) |  | ||||||
|         self.fields["provider"].queryset = ( |  | ||||||
|             Provider.objects.all().order_by("name").select_subclasses() |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     class Meta: |  | ||||||
|  |  | ||||||
|         model = Application |  | ||||||
|         fields = [ |  | ||||||
|             "name", |  | ||||||
|             "slug", |  | ||||||
|             "provider", |  | ||||||
|             "meta_launch_url", |  | ||||||
|             "meta_icon", |  | ||||||
|             "meta_description", |  | ||||||
|             "meta_publisher", |  | ||||||
|         ] |  | ||||||
|         widgets = { |  | ||||||
|             "name": forms.TextInput(), |  | ||||||
|             "meta_launch_url": forms.TextInput(), |  | ||||||
|             "meta_publisher": forms.TextInput(), |  | ||||||
|             "meta_icon": forms.FileInput(), |  | ||||||
|         } |  | ||||||
|         help_texts = { |  | ||||||
|             "meta_launch_url": _( |  | ||||||
|                 ( |  | ||||||
|                     "If left empty, authentik will try to extract the launch URL " |  | ||||||
|                     "based on the selected provider." |  | ||||||
|                 ) |  | ||||||
|             ), |  | ||||||
|         } |  | ||||||
|         field_classes = {"provider": GroupedModelChoiceField} |  | ||||||
|         labels = { |  | ||||||
|             "meta_launch_url": _("Launch URL"), |  | ||||||
|             "meta_icon": _("Icon"), |  | ||||||
|             "meta_description": _("Description"), |  | ||||||
|             "meta_publisher": _("Publisher"), |  | ||||||
|         } |  | ||||||
| @ -1340,10 +1340,8 @@ paths: | |||||||
|           required: true |           required: true | ||||||
|           type: file |           type: file | ||||||
|       responses: |       responses: | ||||||
|         '201': |         '200': | ||||||
|           description: '' |           description: Success | ||||||
|           schema: |  | ||||||
|             $ref: '#/definitions/Application' |  | ||||||
|         '403': |         '403': | ||||||
|           description: Authentication credentials were invalid, absent or insufficient. |           description: Authentication credentials were invalid, absent or insufficient. | ||||||
|           schema: |           schema: | ||||||
|  | |||||||
| @ -1,9 +1,5 @@ | |||||||
| export class AdminURLManager { | export class AdminURLManager { | ||||||
|  |  | ||||||
|     static applications(rest: string): string { |  | ||||||
|         return `/administration/applications/${rest}`; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static policies(rest: string): string { |     static policies(rest: string): string { | ||||||
|         return `/administration/policies/${rest}`; |         return `/administration/policies/${rest}`; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -54,11 +54,18 @@ export class ModalButton extends LitElement { | |||||||
|         super(); |         super(); | ||||||
|         window.addEventListener("keyup", (e) => { |         window.addEventListener("keyup", (e) => { | ||||||
|             if (e.code === "Escape") { |             if (e.code === "Escape") { | ||||||
|  |                 this.resetForms(); | ||||||
|                 this.open = false; |                 this.open = false; | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     resetForms(): void { | ||||||
|  |         this.querySelectorAll<HTMLFormElement>("[slot=form]").forEach(form => { | ||||||
|  |             form.reset(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     updateHandlers(): void { |     updateHandlers(): void { | ||||||
|         // Ensure links close the modal |         // Ensure links close the modal | ||||||
|         this.shadowRoot?.querySelectorAll<HTMLAnchorElement>("a").forEach((a) => { |         this.shadowRoot?.querySelectorAll<HTMLAnchorElement>("a").forEach((a) => { | ||||||
|  | |||||||
| @ -43,6 +43,40 @@ export class Form<T> extends LitElement { | |||||||
|         return this.successMessage; |         return this.successMessage; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Reset the inner iron-form | ||||||
|  |      */ | ||||||
|  |     reset(): void { | ||||||
|  |         const ironForm = this.shadowRoot?.querySelector("iron-form"); | ||||||
|  |         if (!ironForm) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         ironForm.reset(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * If this form contains a file input, and the input as been filled, this function returns | ||||||
|  |      * said file. | ||||||
|  |      * @returns File object or undefined | ||||||
|  |      */ | ||||||
|  |     getFormFile(): File | undefined { | ||||||
|  |         const ironForm = this.shadowRoot?.querySelector("iron-form"); | ||||||
|  |         if (!ironForm) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         const elements = ironForm._getSubmittableElements(); | ||||||
|  |         for (let i = 0; i < elements.length; i++) { | ||||||
|  |             const element = elements[i] as HTMLInputElement; | ||||||
|  |             if (element.tagName.toLowerCase() === "input" && element.type === "file") { | ||||||
|  |                 if ((element.files || []).length < 1) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |                 // We already checked the length | ||||||
|  |                 return (element.files || [])[0]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     serializeForm(form: IronFormElement): T { |     serializeForm(form: IronFormElement): T { | ||||||
|         const elements = form._getSubmittableElements(); |         const elements = form._getSubmittableElements(); | ||||||
|         const json: { [key: string]: unknown } = {}; |         const json: { [key: string]: unknown } = {}; | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ export class ModalForm extends ModalButton { | |||||||
|             } |             } | ||||||
|             formPromise.then(() => { |             formPromise.then(() => { | ||||||
|                 this.open = false; |                 this.open = false; | ||||||
|  |                 form.reset(); | ||||||
|                 this.dispatchEvent( |                 this.dispatchEvent( | ||||||
|                     new CustomEvent(EVENT_REFRESH, { |                     new CustomEvent(EVENT_REFRESH, { | ||||||
|                         bubbles: true, |                         bubbles: true, | ||||||
|  | |||||||
							
								
								
									
										124
									
								
								web/src/pages/applications/ApplicationForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								web/src/pages/applications/ApplicationForm.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | |||||||
|  | import { CoreApi, Application, ProvidersApi, Provider } 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"; | ||||||
|  | import "../../elements/CodeMirror"; | ||||||
|  |  | ||||||
|  | @customElement("ak-application-form") | ||||||
|  | export class ApplicationForm extends Form<Application> { | ||||||
|  |  | ||||||
|  |     @property({ attribute: false }) | ||||||
|  |     application?: Application; | ||||||
|  |  | ||||||
|  |     @property({ attribute: false }) | ||||||
|  |     provider?: number; | ||||||
|  |  | ||||||
|  |     getSuccessMessage(): string { | ||||||
|  |         if (this.application) { | ||||||
|  |             return gettext("Successfully updated application."); | ||||||
|  |         } else { | ||||||
|  |             return gettext("Successfully created application."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send = (data: Application): Promise<Application> => { | ||||||
|  |         let writeOp: Promise<Application>; | ||||||
|  |         if (this.application) { | ||||||
|  |             writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsUpdate({ | ||||||
|  |                 slug: this.application.slug, | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             writeOp = new CoreApi(DEFAULT_CONFIG).coreApplicationsCreate({ | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |         const icon = this.getFormFile(); | ||||||
|  |         if (icon) { | ||||||
|  |             return writeOp.then(app => { | ||||||
|  |                 return new CoreApi(DEFAULT_CONFIG).coreApplicationsSetIcon({ | ||||||
|  |                     slug: app.slug, | ||||||
|  |                     file: icon | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |         return writeOp; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     groupProviders(providers: Provider[]): TemplateResult { | ||||||
|  |         const m = new Map<string, Provider[]>(); | ||||||
|  |         providers.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, providers]) => { | ||||||
|  |                 return html`<optgroup label=${group}> | ||||||
|  |                     ${providers.map(p => { | ||||||
|  |                         const selected = (this.application?.provider?.pk === p.pk) || (this.provider === p.pk) | ||||||
|  |                         return html`<option ?selected=${selected} value=${ifDefined(p.pk)}>${p.name}</option>`; | ||||||
|  |                     })} | ||||||
|  |                 </optgroup>`; | ||||||
|  |             })} | ||||||
|  |         `; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     renderForm(): TemplateResult { | ||||||
|  |         return html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Name")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="name"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.application?.name)}" class="pf-c-form-control" required> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Application's display Name.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Slug")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="slug"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.application?.slug)}" class="pf-c-form-control" required> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Internal application name, used in URLs.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Provider")} | ||||||
|  |                 name="parent"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value="" ?selected=${this.application?.provider === undefined}>---------</option> | ||||||
|  |                     ${until(new ProvidersApi(DEFAULT_CONFIG).providersAllList({}).then(providers => { | ||||||
|  |                         return this.groupProviders(providers.results); | ||||||
|  |                     }), html``)} | ||||||
|  |                 </select> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Launch URL")} | ||||||
|  |                 name="launchUrl"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.application?.launchUrl)}" class="pf-c-form-control"> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("If left empty, authentik will try to extract the launch URL based on the selected provider.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Icon")} | ||||||
|  |                 name="metaIcon"> | ||||||
|  |                 <input type="file" value="${ifDefined(this.application?.metaIcon)}" class="pf-c-form-control"> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Description")} | ||||||
|  |                 name="metaDescription"> | ||||||
|  |                 <textarea class="pf-c-form-control">${ifDefined(this.application?.metaDescription)}</textarea> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Publisher")} | ||||||
|  |                 name="metaPublisher"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.application?.metaPublisher)}" class="pf-c-form-control"> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |         </form>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -1,17 +1,17 @@ | |||||||
| import { gettext } from "django"; | import { gettext } from "django"; | ||||||
| import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element"; | import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element"; | ||||||
|  | import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css"; | ||||||
| import { AKResponse } from "../../api/Client"; | import { AKResponse } from "../../api/Client"; | ||||||
| import { TablePage } from "../../elements/table/TablePage"; | import { TablePage } from "../../elements/table/TablePage"; | ||||||
|  |  | ||||||
| import "../../elements/buttons/ModalButton"; | import "../../elements/forms/ModalForm"; | ||||||
| import "../../elements/forms/DeleteForm"; | import "../../elements/forms/DeleteForm"; | ||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../elements/buttons/SpinnerButton"; | ||||||
| import { TableColumn } from "../../elements/table/Table"; | import { TableColumn } from "../../elements/table/Table"; | ||||||
| import { PAGE_SIZE } from "../../constants"; | import { PAGE_SIZE } from "../../constants"; | ||||||
| import { Application, CoreApi } from "authentik-api"; | import { Application, CoreApi } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../api/Config"; | ||||||
| import { AdminURLManager } from "../../api/legacy"; | import "./ApplicationForm"; | ||||||
| import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css"; |  | ||||||
|  |  | ||||||
| @customElement("ak-application-list") | @customElement("ak-application-list") | ||||||
| export class ApplicationListPage extends TablePage<Application> { | export class ApplicationListPage extends TablePage<Application> { | ||||||
| @ -74,15 +74,22 @@ export class ApplicationListPage extends TablePage<Application> { | |||||||
|                 ${item.metaPublisher ? html`<small>${item.metaPublisher}</small>` : html``} |                 ${item.metaPublisher ? html`<small>${item.metaPublisher}</small>` : html``} | ||||||
|             </a>`, |             </a>`, | ||||||
|             html`<code>${item.slug}</code>`, |             html`<code>${item.slug}</code>`, | ||||||
|             html`${item.provider?.name}`, |             html`${item.provider?.name || "-"}`, | ||||||
|             html`${item.provider?.verboseName}`, |             html`${item.provider?.verboseName || "-"}`, | ||||||
|             html` |             html` | ||||||
|             <ak-modal-button href="${AdminURLManager.applications(`${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 Application")} | ||||||
|  |                 </span> | ||||||
|  |                 <ak-application-form slot="form" .application=${item}> | ||||||
|  |                 </ak-application-form> | ||||||
|  |                 <button slot="trigger" class="pf-c-button pf-m-secondary"> | ||||||
|                     ${gettext("Edit")} |                     ${gettext("Edit")} | ||||||
|                 </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("Application")} |                 objectLabel=${gettext("Application")} | ||||||
| @ -100,12 +107,19 @@ export class ApplicationListPage extends TablePage<Application> { | |||||||
|  |  | ||||||
|     renderToolbar(): TemplateResult { |     renderToolbar(): TemplateResult { | ||||||
|         return html` |         return html` | ||||||
|         <ak-modal-button href=${AdminURLManager.applications("create/")}> |         <ak-forms-modal> | ||||||
|             <ak-spinner-button slot="trigger" class="pf-m-primary"> |             <span slot="submit"> | ||||||
|                 ${gettext("Create")} |                 ${gettext("Create")} | ||||||
|             </ak-spinner-button> |             </span> | ||||||
|             <div slot="modal"></div> |             <span slot="header"> | ||||||
|         </ak-modal-button> |                 ${gettext("Create Application")} | ||||||
|  |             </span> | ||||||
|  |             <ak-application-form slot="form"> | ||||||
|  |             </ak-application-form> | ||||||
|  |             <button slot="trigger" class="pf-c-button pf-m-primary"> | ||||||
|  |                 ${gettext("Create")} | ||||||
|  |             </button> | ||||||
|  |         </ak-forms-modal> | ||||||
|         ${super.renderToolbar()} |         ${super.renderToolbar()} | ||||||
|         `; |         `; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -10,7 +10,6 @@ import { TableColumn } from "../../elements/table/Table"; | |||||||
| import { PAGE_SIZE } from "../../constants"; | import { PAGE_SIZE } from "../../constants"; | ||||||
| import { EventsApi, NotificationRule } from "authentik-api"; | import { EventsApi, NotificationRule } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../api/Config"; | ||||||
| import { AdminURLManager } from "../../api/legacy"; |  | ||||||
| import "../../elements/forms/DeleteForm"; | import "../../elements/forms/DeleteForm"; | ||||||
| import "./RuleForm"; | import "./RuleForm"; | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,14 +1,21 @@ | |||||||
| import { gettext } from "django"; | import { gettext } from "django"; | ||||||
| import { customElement, html, LitElement, property, TemplateResult } from "lit-element"; | import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; | ||||||
| import { Provider } from "authentik-api"; | import { Provider } from "authentik-api"; | ||||||
| import { AdminURLManager } from "../../api/legacy"; | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
|  | import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||||
|  |  | ||||||
| import "../../elements/buttons/ModalButton"; | import "../../elements/buttons/ModalButton"; | ||||||
| import "../../elements/Spinner"; | import "../../elements/Spinner"; | ||||||
|  | import "../../elements/forms/ModalForm"; | ||||||
|  | import "../../pages/applications/ApplicationForm"; | ||||||
|  |  | ||||||
| @customElement("ak-provider-related-application") | @customElement("ak-provider-related-application") | ||||||
| export class RelatedApplicationButton extends LitElement { | export class RelatedApplicationButton extends LitElement { | ||||||
|  |  | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return [PFBase, PFButton]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @property({attribute: false}) |     @property({attribute: false}) | ||||||
|     provider?: Provider; |     provider?: Provider; | ||||||
|  |  | ||||||
| @ -18,12 +25,19 @@ export class RelatedApplicationButton extends LitElement { | |||||||
|                 ${this.provider.assignedApplicationName} |                 ${this.provider.assignedApplicationName} | ||||||
|             </a>`; |             </a>`; | ||||||
|         } |         } | ||||||
|         return html`<ak-modal-button href=${AdminURLManager.applications(`create/?provider=${this.provider ? this.provider.pk : ""}`)}> |         return html`<ak-forms-modal> | ||||||
|                 <ak-spinner-button slot="trigger" class="pf-m-primary"> |             <span slot="submit"> | ||||||
|                     ${gettext("Create")} |                 ${gettext("Create")} | ||||||
|                 </ak-spinner-button> |             </span> | ||||||
|                 <div slot="modal"></div> |             <span slot="header"> | ||||||
|             </ak-modal-button>`; |                 ${gettext("Create Application")} | ||||||
|  |             </span> | ||||||
|  |             <ak-application-form slot="form" .provider=${this.provider?.pk}> | ||||||
|  |             </ak-application-form> | ||||||
|  |             <button slot="trigger" class="pf-c-button pf-m-primary"> | ||||||
|  |                 ${gettext("Create")} | ||||||
|  |             </button> | ||||||
|  |         </ak-forms-modal>`; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer