Remove expert fields, add form config

This commit is contained in:
Tobias Kunze 2025-11-05 08:57:28 +01:00
parent 1cf1947539
commit 357e39b543
6 changed files with 80 additions and 44 deletions

View file

@ -1,3 +1,6 @@
import json
from pathlib import Path
from django.contrib import admin, messages
from django.utils.translation import gettext_lazy as _
from django_jsonform.widgets import JSONFormWidget
@ -313,9 +316,9 @@ class ServiceDefinitionAdmin(admin.ModelAdmin):
(
_("Form Configuration"),
{
"fields": ("advanced_fields",),
"fields": ("form_config",),
"description": _(
"Configure which fields should be hidden behind an 'Advanced' toggle in the form"
"Optional custom form configuration. When provided, this will be used instead of auto-generating the form from the OpenAPI spec."
),
},
),
@ -323,19 +326,13 @@ class ServiceDefinitionAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
# JSON schema for advanced_fields field
advanced_fields_schema = {
"type": "array",
"title": "Advanced Fields",
"items": {
"type": "string",
"title": "Field Name",
"description": "Field name in dot notation (e.g., spec.parameters.monitoring.enabled)",
},
}
if "advanced_fields" in form.base_fields:
form.base_fields["advanced_fields"].widget = JSONFormWidget(
schema=advanced_fields_schema
schema_path = Path(__file__).parent / "schemas" / "form_config_schema.json"
with open(schema_path) as f:
form_config_schema = json.load(f)
if "form_config" in form.base_fields:
form.base_fields["form_config"].widget = JSONFormWidget(
schema=form_config_schema
)
return form

View file

@ -0,0 +1,32 @@
# Generated by Django 5.2.7 on 2025-10-31 10:40
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("core", "0011_alter_organizationorigin_billing_entity"),
]
operations = [
migrations.RemoveField(
model_name="servicedefinition",
name="advanced_fields",
),
migrations.AlterField(
model_name="organization",
name="name",
field=models.CharField(
max_length=32,
validators=[
django.core.validators.RegexValidator(
message="Organization name can only contain letters, numbers, and spaces.",
regex="^[A-Za-z0-9\\s]+$",
)
],
verbose_name="Name",
),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 5.2.7 on 2025-10-31 10:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("core", "0012_remove_advanced_fields"),
]
operations = [
migrations.AddField(
model_name="servicedefinition",
name="form_config",
field=models.JSONField(
blank=True,
help_text='Optional custom form configuration. When provided, this configuration will be used to render the service form instead of auto-generating it from the OpenAPI spec. Format: {"fieldsets": [{"title": "Section", "fields": [{...}]}]}',
null=True,
verbose_name="Form Configuration",
),
),
]

View file

@ -365,7 +365,7 @@ class ServiceDefinition(ServalaModelMixin, models.Model):
help_text=_(
"Optional custom form configuration. When provided, this configuration will be used "
"to render the service form instead of auto-generating it from the OpenAPI spec. "
"Format: {\"fieldsets\": [{\"title\": \"Section\", \"fields\": [{...}]}]}"
'Format: {"fieldsets": [{"title": "Section", "fields": [{...}]}]}'
),
null=True,
blank=True,

View file

@ -48,9 +48,6 @@
"description": "Whether the field is required",
"default": false
},
"default": {
"description": "Default value for the field"
},
"controlplane_field_mapping": {
"type": "string",
"description": "Dot-notation path mapping to Kubernetes spec field (e.g., 'spec.parameters.service.fqdn')"
@ -78,12 +75,9 @@
"description": "Array of [value, label] pairs for choice fields",
"items": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"items": [
{"type": "string"},
{"type": "string"}
]
"items": {
"type": "string"
}
}
},
"min_values": {
@ -112,17 +106,7 @@
"enum": ["suggest_fqdn_from_name"]
}
}
},
"allOf": [
{
"if": {
"properties": {"type": {"const": "choice"}}
},
"then": {
"required": ["choices"]
}
}
]
}
}
}
}

View file

@ -237,42 +237,42 @@ a.btn-keycloak {
flex-grow: 1;
}
/* CRD Form mandatory field styling */
.crd-form .form-group.mandatory .form-label {
/* Expert CRD Form mandatory field styling */
.expert-crd-form .form-group.mandatory .form-label {
font-weight: bold;
position: relative;
}
.crd-form .form-group.mandatory .form-label::after {
.expert-crd-form .form-group.mandatory .form-label::after {
content: " *";
color: #dc3545;
font-weight: bold;
}
.crd-form .form-group.mandatory {
.expert-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 {
.expert-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 {
html[data-bs-theme="dark"] .expert-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 {
html[data-bs-theme="dark"] .expert-crd-form .form-group.mandatory .form-label::after {
color: #ff6b6b;
}
html[data-bs-theme="dark"] .crd-form .nav-tabs .nav-link .mandatory-indicator {
html[data-bs-theme="dark"] .expert-crd-form .nav-tabs .nav-link .mandatory-indicator {
color: #ff6b6b;
}