From 36387e76f981d952a93e25369591a868cd38f25b Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Fri, 5 Sep 2025 14:51:46 +0200 Subject: [PATCH] Make mandatory fields in CRD forms more prominent --- src/servala/core/crd.py | 29 ++++++++++++- .../includes/tabbed_fieldset_form.html | 5 ++- src/servala/static/css/servala.css | 43 +++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/servala/core/crd.py b/src/servala/core/crd.py index f9fbd32..f01e50b 100644 --- a/src/servala/core/crd.py +++ b/src/servala/core/crd.py @@ -229,6 +229,12 @@ class CrdModelFormMixin: if field and field.label and (position := field.label.find(label)) != -1: field.label = field.label[position + len(label) :] + def has_mandatory_fields(self, field_list): + for field_name in field_list: + if field_name in self.fields and self.fields[field_name].required: + return True + return False + def get_fieldsets(self): fieldsets = [] @@ -239,7 +245,12 @@ class CrdModelFormMixin: if not field_name.startswith("spec.") ] if general_fields: - fieldset = {"title": "General", "fields": general_fields, "fieldsets": []} + fieldset = { + "title": "General", + "fields": general_fields, + "fieldsets": [], + "has_mandatory": self.has_mandatory_fields(general_fields), + } if all( [ isinstance(self.fields[field].widget, forms.HiddenInput) @@ -315,11 +326,24 @@ class CrdModelFormMixin: title = f"{fieldset['title']}: " for field in fieldset["fields"]: self.strip_title(field, title) + + all_fields = fieldset["fields"][:] + for sub_fieldset in nested_fieldsets_list: + all_fields.extend(sub_fieldset["fields"]) + fieldset["has_mandatory"] = self.has_mandatory_fields(all_fields) + fieldsets.append(fieldset) # Add 'others' tab if there are any fields if others: - fieldsets.append({"title": "Others", "fields": others, "fieldsets": []}) + fieldsets.append( + { + "title": "Others", + "fields": others, + "fieldsets": [], + "has_mandatory": self.has_mandatory_fields(others), + } + ) if hidden_spec_fields: fieldsets.append( @@ -328,6 +352,7 @@ class CrdModelFormMixin: "fields": hidden_spec_fields, "fieldsets": [], "hidden": True, + "has_mandatory": self.has_mandatory_fields(hidden_spec_fields), } ) diff --git a/src/servala/frontend/templates/includes/tabbed_fieldset_form.html b/src/servala/frontend/templates/includes/tabbed_fieldset_form.html index e304c33..c36f06f 100644 --- a/src/servala/frontend/templates/includes/tabbed_fieldset_form.html +++ b/src/servala/frontend/templates/includes/tabbed_fieldset_form.html @@ -1,6 +1,6 @@ {% load i18n %} {% load get_field %} -
{% csrf_token %} @@ -8,7 +8,7 @@ {% for fieldset in form.get_fieldsets %} {% if not fieldset.hidden %} {% endif %} diff --git a/src/servala/static/css/servala.css b/src/servala/static/css/servala.css index ee4c080..2390b97 100644 --- a/src/servala/static/css/servala.css +++ b/src/servala/static/css/servala.css @@ -192,3 +192,46 @@ a.btn-keycloak { .service-cards-container .card-footer { margin-top: auto; } + +/* CRD Form mandatory field styling */ +.crd-form .form-group.mandatory .form-label { + font-weight: bold; + position: relative; +} + +.crd-form .form-group.mandatory .form-label::after { + content: " *"; + color: #dc3545; + font-weight: bold; +} + +.crd-form .form-group.mandatory { + border-left: 3px solid #dc3545; + padding-left: 10px; + background-color: rgba(220, 53, 69, 0.05); + border-radius: 3px; +} + +.crd-form .nav-tabs .nav-link .mandatory-indicator { + color: #dc3545; + font-weight: bold; + font-size: 1.1em; + margin-left: 4px; +} + +html[data-bs-theme="dark"] .crd-form .form-group.mandatory { + background-color: rgba(220, 53, 69, 0.1); + border-left-color: #ff6b6b; +} + +html[data-bs-theme="dark"] .crd-form .form-group.mandatory .form-label::after { + color: #ff6b6b; +} + +html[data-bs-theme="dark"] .crd-form .nav-tabs .nav-link .mandatory-indicator { + color: #ff6b6b; +} + +.crd-form .nav-tabs .nav-link.has-mandatory { + position: relative; +}