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',