From d38ace89ce3e6fa0d0539e43baaa74cc376b4cf7 Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Tue, 18 Aug 2026 08:30:45 -0500 Subject: [PATCH] Fixes #22889: Render Config Revision banner fields in monospace (#22907) Replace the obsolete Django admin `vLargeTextField` class with Tabler's `font-monospace` utility for the four banner configuration parameters. Define the widget styling in the parameter definitions, where the metaclass constructs the form fields, and remove the ineffective `Meta.widgets` overrides. Add regression coverage for all six code-oriented configuration fields, including the two JSON fields that already use a monospace font. Update the add-config-param skill to recommend `font-monospace` so future textarea-backed parameters do not reintroduce the obsolete admin class. --- .claude/skills/add-config-param/SKILL.md | 2 +- netbox/core/forms/model_forms.py | 6 ------ netbox/core/tests/test_forms.py | 25 ++++++++++++++++++++++++ netbox/netbox/config/parameters.py | 8 ++++---- 4 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 netbox/core/tests/test_forms.py diff --git a/.claude/skills/add-config-param/SKILL.md b/.claude/skills/add-config-param/SKILL.md index 429705cb9..5eb2a25af 100644 --- a/.claude/skills/add-config-param/SKILL.md +++ b/.claude/skills/add-config-param/SKILL.md @@ -43,7 +43,7 @@ ConfigParam( field=forms.BooleanField, # or IntegerField, CharField, JSONField, SimpleArrayField # field_kwargs only when extra widget/validation config is needed: field_kwargs={ - 'widget': forms.Textarea(attrs={'class': 'vLargeTextField'}), + 'widget': forms.Textarea(attrs={'class': 'font-monospace'}), }, ), ``` diff --git a/netbox/core/forms/model_forms.py b/netbox/core/forms/model_forms.py index aca3d9fd3..963007154 100644 --- a/netbox/core/forms/model_forms.py +++ b/netbox/core/forms/model_forms.py @@ -168,12 +168,6 @@ class ConfigRevisionForm(forms.ModelForm, metaclass=ConfigFormMetaclass): model = ConfigRevision fields = '__all__' widgets = { - 'BANNER_LOGIN': forms.Textarea(attrs={'class': 'font-monospace'}), - 'BANNER_MAINTENANCE': forms.Textarea(attrs={'class': 'font-monospace'}), - 'BANNER_TOP': forms.Textarea(attrs={'class': 'font-monospace'}), - 'BANNER_BOTTOM': forms.Textarea(attrs={'class': 'font-monospace'}), - 'CUSTOM_VALIDATORS': forms.Textarea(attrs={'class': 'font-monospace'}), - 'PROTECTION_RULES': forms.Textarea(attrs={'class': 'font-monospace'}), 'comment': forms.Textarea(), } diff --git a/netbox/core/tests/test_forms.py b/netbox/core/tests/test_forms.py new file mode 100644 index 000000000..d351ee295 --- /dev/null +++ b/netbox/core/tests/test_forms.py @@ -0,0 +1,25 @@ +from django.test import TestCase + +from core.forms import ConfigRevisionForm + + +class ConfigRevisionFormTestCase(TestCase): + + def test_code_fields_render_monospace(self): + """ + Config parameters that hold markup or code (banners, JSON) must render their + textareas in a monospace font. See #8974 and #22889. + """ + form = ConfigRevisionForm() + monospace_fields = ( + 'BANNER_LOGIN', + 'BANNER_MAINTENANCE', + 'BANNER_TOP', + 'BANNER_BOTTOM', + 'CUSTOM_VALIDATORS', + 'PROTECTION_RULES', + ) + for name in monospace_fields: + with self.subTest(field=name): + css_classes = form[name].field.widget.attrs.get('class', '').split() + self.assertIn('font-monospace', css_classes) diff --git a/netbox/netbox/config/parameters.py b/netbox/netbox/config/parameters.py index 69d62033b..204645a12 100644 --- a/netbox/netbox/config/parameters.py +++ b/netbox/netbox/config/parameters.py @@ -24,7 +24,7 @@ PARAMS = ( description=_("Additional content to display on the login page"), field_kwargs={ 'widget': forms.Textarea( - attrs={'class': 'vLargeTextField'} + attrs={'class': 'font-monospace'} ), }, ), @@ -35,7 +35,7 @@ PARAMS = ( description=_('Additional content to display when in maintenance mode'), field_kwargs={ 'widget': forms.Textarea( - attrs={'class': 'vLargeTextField'} + attrs={'class': 'font-monospace'} ), }, ), @@ -46,7 +46,7 @@ PARAMS = ( description=_("Additional content to display at the top of every page"), field_kwargs={ 'widget': forms.Textarea( - attrs={'class': 'vLargeTextField'} + attrs={'class': 'font-monospace'} ), }, ), @@ -57,7 +57,7 @@ PARAMS = ( description=_("Additional content to display at the bottom of every page"), field_kwargs={ 'widget': forms.Textarea( - attrs={'class': 'vLargeTextField'} + attrs={'class': 'font-monospace'} ), }, ),