feat(16.2-01): compile, decode and load plugin field types in cabana

- compileFieldTypes builds a per-boot field type registry (alias, core and
  cross-plugin collisions, element prefix, assets, option keys) passed down
  the compile functions; settings and relation forms refuse plugin aliases
- fields.yaml accepts a plugin alias with the general keys plus the type's
  options (typeOptions, element, translatable in the schema); CheckOptions
  runs at boot; CompileFormWithTypes for plugin tests
- save decodes plugin values inside the transaction (FormFieldError is a
  422, other errors opaque 500) and answers meta.notices (FieldNotice) only
  when a type reported something; show and save serve values through Load
- GET /field-types lists the types with versioned asset URLs; OpenAPI,
  schema.d.ts, README and docs/backend/field-types.md updated
This commit is contained in:
2026-10-10 11:06:12 +02:00
parent 1e20ace15c
commit 717d46ec3d
21 changed files with 1617 additions and 73 deletions

View File

@@ -295,6 +295,13 @@ type relationColumnDocument struct {
}
func compileRelations(pluginID string, ctl pact.AdminController, fsys fs.FS, form *FormSchema) (map[string]*CompiledRelation, error) {
return compileRelationsWithTypes(pluginID, ctl, fsys, form, nil)
}
// compileRelationsWithTypes is compileRelations with the plugin field types
// of the boot: relation forms refuse them (supported in controller forms
// only).
func compileRelationsWithTypes(pluginID string, ctl pact.AdminController, fsys fs.FS, form *FormSchema, types *fieldTypeRegistry) (map[string]*CompiledRelation, error) {
// fields maps each relation-manager relation to its form field index.
fields := map[string]int{}
if form != nil {
@@ -381,7 +388,7 @@ func compileRelations(pluginID string, ctl pact.AdminController, fsys fs.FS, for
fieldName: form.Fields[fields[name]].Name,
}
schema.Deferrable = cr.deferrable
if err := compileRelationForms(pluginID, ctl, fsys, file, doc, cr); err != nil {
if err := compileRelationForms(pluginID, ctl, fsys, file, doc, cr, types); err != nil {
return nil, err
}
form.Fields[fields[name]].Deferrable = cr.deferrable