diff --git a/passbook/admin/fields.py b/passbook/admin/fields.py index 4510ec846..67ebac8e0 100644 --- a/passbook/admin/fields.py +++ b/passbook/admin/fields.py @@ -4,6 +4,27 @@ from django import forms from django.utils.translation import gettext_lazy as _ +class CodeMirrorWidget(forms.Textarea): + """Custom Textarea-based Widget that triggers a CodeMirror editor""" + + # CodeMirror mode to enable + mode: str + + def __init__(self, *args, mode="yaml", **kwargs): + super().__init__(*args, **kwargs) + self.mode = mode + + def render(self, *args, **kwargs): + if "attrs" not in kwargs: + kwargs["attrs"] = {} + attrs = kwargs["attrs"] + if "class" not in attrs: + attrs["class"] = "" + attrs["class"] += " codemirror" + attrs["data-cm-mode"] = self.mode + return super().render(*args, **kwargs) + + class InvalidYAMLInput(str): """Invalid YAML String type""" diff --git a/passbook/admin/forms/users.py b/passbook/admin/forms/users.py index f81b22a8d..c3a640396 100644 --- a/passbook/admin/forms/users.py +++ b/passbook/admin/forms/users.py @@ -2,7 +2,7 @@ from django import forms -from passbook.admin.fields import YAMLField +from passbook.admin.fields import CodeMirrorWidget, YAMLField from passbook.core.models import User @@ -15,6 +15,7 @@ class UserForm(forms.ModelForm): fields = ["username", "name", "email", "is_staff", "is_active", "attributes"] widgets = { "name": forms.TextInput, + "attributes": CodeMirrorWidget, } field_classes = { "attributes": YAMLField, diff --git a/passbook/admin/templates/administration/base.html b/passbook/admin/templates/administration/base.html index 1bcdd6fb3..72a316a5f 100644 --- a/passbook/admin/templates/administration/base.html +++ b/passbook/admin/templates/administration/base.html @@ -66,6 +66,12 @@ {% trans 'Flows' %} +
  • + + {% trans 'Bindings' %} + +
  • @@ -84,12 +90,6 @@ {% trans 'Invitations' %}
  • -
  • - - {% trans 'Bindings' %} - -
  • diff --git a/passbook/admin/templates/generic/form.html b/passbook/admin/templates/generic/form.html index 791f2e9e6..1d535b5dd 100644 --- a/passbook/admin/templates/generic/form.html +++ b/passbook/admin/templates/generic/form.html @@ -48,28 +48,6 @@ - {% endblock %} {% block scripts %} diff --git a/passbook/policies/expression/forms.py b/passbook/policies/expression/forms.py index 50747a3cd..54117958d 100644 --- a/passbook/policies/expression/forms.py +++ b/passbook/policies/expression/forms.py @@ -2,6 +2,7 @@ from django import forms +from passbook.admin.fields import CodeMirrorWidget from passbook.policies.expression.models import ExpressionPolicy from passbook.policies.forms import GENERAL_FIELDS @@ -19,4 +20,5 @@ class ExpressionPolicyForm(forms.ModelForm): ] widgets = { "name": forms.TextInput(), + "expression": CodeMirrorWidget(mode="jinja2"), } diff --git a/passbook/stages/invitation/forms.py b/passbook/stages/invitation/forms.py index a6a34d17e..620d14db5 100644 --- a/passbook/stages/invitation/forms.py +++ b/passbook/stages/invitation/forms.py @@ -2,6 +2,7 @@ from django import forms from django.utils.translation import gettext as _ +from passbook.admin.fields import CodeMirrorWidget, YAMLField from passbook.stages.invitation.models import Invitation, InvitationStage @@ -27,7 +28,5 @@ class InvitationForm(forms.ModelForm): labels = { "fixed_data": _("Optional fixed data to enforce on user enrollment."), } - widgets = { - "fixed_username": forms.TextInput(), - "fixed_email": forms.TextInput(), - } + widgets = {"fixed_data": CodeMirrorWidget} + field_classes = {"fixed_data": YAMLField} diff --git a/passbook/static/static/passbook/pf.js b/passbook/static/static/passbook/pf.js index 3e27016ed..54cb8f9ff 100644 --- a/passbook/static/static/passbook/pf.js +++ b/passbook/static/static/passbook/pf.js @@ -28,6 +28,8 @@ document.querySelectorAll(".codemirror").forEach((cm) => { if ('data-cm-mode' in cm.attributes) { cmMode = cm.attributes['data-cm-mode'].value; } + // https://github.com/codemirror/CodeMirror/issues/5092 + cm.removeAttribute("required"); CodeMirror.fromTextArea(cm, { mode: cmMode, theme: 'monokai',