web/elements: add support for non-field errors
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		| @ -1,7 +1,12 @@ | |||||||
| """policy binding API Views""" | """policy binding API Views""" | ||||||
| from typing import OrderedDict | from typing import OrderedDict | ||||||
|  |  | ||||||
| from django.core.exceptions import ObjectDoesNotExist | from django.core.exceptions import ObjectDoesNotExist | ||||||
| from rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField, ValidationError | from rest_framework.serializers import ( | ||||||
|  |     ModelSerializer, | ||||||
|  |     PrimaryKeyRelatedField, | ||||||
|  |     ValidationError, | ||||||
|  | ) | ||||||
| from rest_framework.viewsets import ModelViewSet | from rest_framework.viewsets import ModelViewSet | ||||||
| from structlog.stdlib import get_logger | from structlog.stdlib import get_logger | ||||||
|  |  | ||||||
| @ -77,8 +82,7 @@ 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( |         count = sum([bool(data["policy"]), bool(data["group"]), bool(data["user"])]) | ||||||
|             data["group"]), bool(data["user"])]) |  | ||||||
|         invalid = count > 1 |         invalid = count > 1 | ||||||
|         empty = count < 1 |         empty = count < 1 | ||||||
|         if invalid: |         if invalid: | ||||||
| @ -87,6 +91,7 @@ class PolicyBindingSerializer(ModelSerializer): | |||||||
|             raise ValidationError("One of 'policy', 'group' or 'user' must be set.") |             raise ValidationError("One of 'policy', 'group' or 'user' must be set.") | ||||||
|         return data |         return data | ||||||
|  |  | ||||||
|  |  | ||||||
| class PolicyBindingViewSet(ModelViewSet): | class PolicyBindingViewSet(ModelViewSet): | ||||||
|     """PolicyBinding Viewset""" |     """PolicyBinding Viewset""" | ||||||
|  |  | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css"; | |||||||
| import AKGlobal from "../../authentik.css"; | import AKGlobal from "../../authentik.css"; | ||||||
| import PFForm from "@patternfly/patternfly/components/Form/form.css"; | import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||||||
| import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||||||
|  | import PFAlert from "@patternfly/patternfly/components/Alert/alert.css"; | ||||||
| import { MessageLevel } from "../messages/Message"; | import { MessageLevel } from "../messages/Message"; | ||||||
| import { IronFormElement } from "@polymer/iron-form/iron-form"; | import { IronFormElement } from "@polymer/iron-form/iron-form"; | ||||||
| import { camelToSnake } from "../../utils"; | import { camelToSnake } from "../../utils"; | ||||||
| @ -31,8 +32,11 @@ export class Form<T> extends LitElement { | |||||||
|     @property() |     @property() | ||||||
|     send!: (data: T) => Promise<unknown>; |     send!: (data: T) => Promise<unknown>; | ||||||
|  |  | ||||||
|  |     @property({attribute: false}) | ||||||
|  |     nonFieldErrors?: string[]; | ||||||
|  |  | ||||||
|     static get styles(): CSSResult[] { |     static get styles(): CSSResult[] { | ||||||
|         return [PFBase, PFCard, PFButton, PFForm, PFFormControl, AKGlobal, css` |         return [PFBase, PFCard, PFButton, PFForm, PFAlert, PFFormControl, AKGlobal, css` | ||||||
|             select[multiple] { |             select[multiple] { | ||||||
|                 height: 15em; |                 height: 15em; | ||||||
|             } |             } | ||||||
| @ -116,6 +120,7 @@ export class Form<T> extends LitElement { | |||||||
|                     if (errorMessage instanceof Error) { |                     if (errorMessage instanceof Error) { | ||||||
|                         throw errorMessage; |                         throw errorMessage; | ||||||
|                     } |                     } | ||||||
|  |                     // assign all input-related errors to their elements | ||||||
|                     const elements: PaperInputElement[] = ironForm._getSubmittableElements(); |                     const elements: PaperInputElement[] = ironForm._getSubmittableElements(); | ||||||
|                     elements.forEach((element) => { |                     elements.forEach((element) => { | ||||||
|                         const elementName = element.name; |                         const elementName = element.name; | ||||||
| @ -125,6 +130,9 @@ export class Form<T> extends LitElement { | |||||||
|                             element.invalid = true; |                             element.invalid = true; | ||||||
|                         } |                         } | ||||||
|                     }); |                     }); | ||||||
|  |                     if ("non_field_errors" in errorMessage) { | ||||||
|  |                         this.nonFieldErrors = errorMessage["non_field_errors"]; | ||||||
|  |                     } | ||||||
|                     throw new APIError(errorMessage); |                     throw new APIError(errorMessage); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| @ -136,6 +144,24 @@ export class Form<T> extends LitElement { | |||||||
|         return html`<slot></slot>`; |         return html`<slot></slot>`; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     renderNonFieldErrors(): TemplateResult { | ||||||
|  |         if (!this.nonFieldErrors) { | ||||||
|  |             return html``; | ||||||
|  |         } | ||||||
|  |         return html`<div class="pf-c-form__alert"> | ||||||
|  |         ${this.nonFieldErrors.map(err => { | ||||||
|  |             return html`<div class="pf-c-alert pf-m-inline pf-m-danger"> | ||||||
|  |                 <div class="pf-c-alert__icon"> | ||||||
|  |                     <i class="fas fa-exclamation-circle"></i> | ||||||
|  |                 </div> | ||||||
|  |                 <h4 class="pf-c-alert__title"> | ||||||
|  |                     ${err} | ||||||
|  |                 </h4> | ||||||
|  |             </div>`; | ||||||
|  |         })} | ||||||
|  |         </div>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     render(): TemplateResult { |     render(): TemplateResult { | ||||||
|         const rect = this.getBoundingClientRect(); |         const rect = this.getBoundingClientRect(); | ||||||
|         if (rect.x + rect.y + rect.width + rect.height === 0) { |         if (rect.x + rect.y + rect.width + rect.height === 0) { | ||||||
| @ -143,6 +169,7 @@ export class Form<T> extends LitElement { | |||||||
|         } |         } | ||||||
|         return html`<iron-form |         return html`<iron-form | ||||||
|             @iron-form-presubmit=${(ev: Event) => { this.submit(ev); }}> |             @iron-form-presubmit=${(ev: Event) => { this.submit(ev); }}> | ||||||
|  |             ${this.renderNonFieldErrors()} | ||||||
|             ${this.renderForm()} |             ${this.renderForm()} | ||||||
|         </iron-form>`; |         </iron-form>`; | ||||||
|     } |     } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer