Provide form building schema
This commit is contained in:
parent
880d10c5e5
commit
1cf1947539
3 changed files with 163 additions and 0 deletions
|
|
@ -1,3 +1,7 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import jsonschema
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_jsonform.widgets import JSONFormWidget
|
||||
|
|
@ -124,6 +128,10 @@ class ServiceDefinitionAdminForm(forms.ModelForm):
|
|||
self.fields["api_version"].initial = api_def.get("version", "")
|
||||
self.fields["api_kind"].initial = api_def.get("kind", "")
|
||||
|
||||
schema_path = Path(__file__).parent / "schemas" / "form_config_schema.json"
|
||||
with open(schema_path) as f:
|
||||
self.form_config_schema = json.load(f)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
|
|
@ -151,6 +159,19 @@ class ServiceDefinitionAdminForm(forms.ModelForm):
|
|||
api_def["kind"] = api_kind
|
||||
cleaned_data["api_definition"] = api_def
|
||||
|
||||
form_config = cleaned_data.get("form_config")
|
||||
if form_config:
|
||||
try:
|
||||
jsonschema.validate(instance=form_config, schema=self.form_config_schema)
|
||||
except jsonschema.ValidationError as e:
|
||||
raise forms.ValidationError(
|
||||
{"form_config": _("Invalid form configuration: {}").format(e.message)}
|
||||
)
|
||||
except jsonschema.SchemaError as e:
|
||||
raise forms.ValidationError(
|
||||
{"form_config": _("Schema error: {}").format(e.message)}
|
||||
)
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -360,6 +360,16 @@ class ServiceDefinition(ServalaModelMixin, models.Model):
|
|||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
form_config = models.JSONField(
|
||||
verbose_name=_("Form Configuration"),
|
||||
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,
|
||||
blank=True,
|
||||
)
|
||||
service = models.ForeignKey(
|
||||
to="Service",
|
||||
on_delete=models.CASCADE,
|
||||
|
|
|
|||
132
src/servala/core/schemas/form_config_schema.json
Normal file
132
src/servala/core/schemas/form_config_schema.json
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Service Definition Form Configuration Schema",
|
||||
"description": "Schema for custom form configuration in ServiceDefinition",
|
||||
"type": "object",
|
||||
"required": ["fieldsets"],
|
||||
"properties": {
|
||||
"fieldsets": {
|
||||
"type": "array",
|
||||
"description": "Array of fieldset objects defining form sections",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["fields"],
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Optional title for the fieldset/tab"
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"description": "Array of field definitions in this fieldset",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["name", "type", "label", "controlplane_field_mapping"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Unique field name/identifier",
|
||||
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Field type",
|
||||
"enum": ["text", "email", "textarea", "number", "choice", "checkbox", "array"]
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Human-readable field label"
|
||||
},
|
||||
"help_text": {
|
||||
"type": "string",
|
||||
"description": "Optional help text displayed below the field"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean",
|
||||
"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')"
|
||||
},
|
||||
"max_length": {
|
||||
"type": "integer",
|
||||
"description": "Maximum length for text/textarea fields",
|
||||
"minimum": 1
|
||||
},
|
||||
"rows": {
|
||||
"type": "integer",
|
||||
"description": "Number of rows for textarea fields",
|
||||
"minimum": 1
|
||||
},
|
||||
"min_value": {
|
||||
"type": "number",
|
||||
"description": "Minimum value for number fields"
|
||||
},
|
||||
"max_value": {
|
||||
"type": "number",
|
||||
"description": "Maximum value for number fields"
|
||||
},
|
||||
"choices": {
|
||||
"type": "array",
|
||||
"description": "Array of [value, label] pairs for choice fields",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": [
|
||||
{"type": "string"},
|
||||
{"type": "string"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"min_values": {
|
||||
"type": "integer",
|
||||
"description": "Minimum number of values for array fields",
|
||||
"minimum": 0
|
||||
},
|
||||
"max_values": {
|
||||
"type": "integer",
|
||||
"description": "Maximum number of values for array fields",
|
||||
"minimum": 1
|
||||
},
|
||||
"validators": {
|
||||
"type": "array",
|
||||
"description": "Array of validator names (for future use)",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["email", "fqdn", "url", "ipv4", "ipv6"]
|
||||
}
|
||||
},
|
||||
"generators": {
|
||||
"type": "array",
|
||||
"description": "Array of generator function names (for future use)",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["suggest_fqdn_from_name"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {"type": {"const": "choice"}}
|
||||
},
|
||||
"then": {
|
||||
"required": ["choices"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue