Remove expert fields, add form config
This commit is contained in:
parent
1cf1947539
commit
357e39b543
6 changed files with 80 additions and 44 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
32
src/servala/core/migrations/0012_remove_advanced_fields.py
Normal file
32
src/servala/core/migrations/0012_remove_advanced_fields.py
Normal 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",
|
||||
),
|
||||
),
|
||||
]
|
||||
23
src/servala/core/migrations/0013_add_form_config.py
Normal file
23
src/servala/core/migrations/0013_add_form_config.py
Normal 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",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue