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:
109
admin/src/api/schema.d.ts
vendored
109
admin/src/api/schema.d.ts
vendored
@@ -449,6 +449,72 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/field-types": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Plugin field types
|
||||
* @description Every admin form field type a plugin registers (pact.HasFormFieldTypes), sorted by name, with the URLs of its scripts and stylesheets (each with a ?v= content hash). The admin loads every script once after sign-in and keeps every stylesheet enabled on all pages; a form field whose `element` is set renders that custom element. An empty list when no plugin registers a type. Any backend session may call it.
|
||||
*/
|
||||
get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.FieldTypesResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Unauthorized */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
/** @description Not Found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/lang": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -991,7 +1057,7 @@ export interface paths {
|
||||
put?: never;
|
||||
/**
|
||||
* Create an admin record
|
||||
* @description Relation fields are sent by field name with ids ({"genre": 3, "artists": [4, 9]}); the response carries the same shape plus meta.labels.
|
||||
* @description Relation fields are sent by field name with ids ({"genre": 3, "artists": [4, 9]}); the response carries the same shape plus meta.labels. A plugin field type's value is decoded by its type inside the save; when a type reports what it changed, meta.notices lists the localized messages per field (and content locale), and the key is absent otherwise.
|
||||
*/
|
||||
post: {
|
||||
parameters: {
|
||||
@@ -1514,7 +1580,7 @@ export interface paths {
|
||||
};
|
||||
/**
|
||||
* Admin form schema
|
||||
* @description The form of a controller, localized. `preview` is present when config_form.yaml declares a preview block: the form then has a read-only preview screen, which shows the fields whose context allows preview, the record actions and, when preview.headerPartial is set, that partial as a status hint. A `type: password` field and every other field the controller lists as virtual is sent in a save body and never has a value in a record response. `preset` on a text or mltext field names the text or mltext field it follows on the create form (type slug or exact; an mltext pair follows per locale) until the administrator edits it. A `type: permissioneditor` field carries `permissionOptions`, the permissions the controller offers the requesting administrator; its value in a record response and in a save body is an object of permission code to integer (radio mode 1 or -1, checkbox mode 1). A `type: relation` field over a protected foreign key is `readOnly` unless its contract declares the key writable.
|
||||
* @description The form of a controller, localized. `preview` is present when config_form.yaml declares a preview block: the form then has a read-only preview screen, which shows the fields whose context allows preview, the record actions and, when preview.headerPartial is set, that partial as a status hint. A `type: password` field and every other field the controller lists as virtual is sent in a save body and never has a value in a record response. `preset` on a text or mltext field names the text or mltext field it follows on the create form (type slug or exact; an mltext pair follows per locale) until the administrator edits it. A `type: permissioneditor` field carries `permissionOptions`, the permissions the controller offers the requesting administrator; its value in a record response and in a save body is an object of permission code to integer (radio mode 1 or -1, checkbox mode 1). A `type: relation` field over a protected foreign key is `readOnly` unless its contract declares the key writable. A field whose type a plugin registers carries `element` (the custom-element tag the admin renders), `translatable` (its value is an object of content locale to string) and `typeOptions` (the type's own fields.yaml keys).
|
||||
*/
|
||||
get: {
|
||||
parameters: {
|
||||
@@ -1965,7 +2031,10 @@ export interface paths {
|
||||
};
|
||||
};
|
||||
};
|
||||
/** Update an admin record */
|
||||
/**
|
||||
* Update an admin record
|
||||
* @description A plugin field type's value is decoded by its type inside the save. When a type reports what it changed, meta.notices lists the localized messages per field (and content locale), and the key is absent otherwise.
|
||||
*/
|
||||
put: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -4694,10 +4763,26 @@ export interface components {
|
||||
"cabana.ErrorEnvelope": {
|
||||
error: components["schemas"]["cabana.ErrorBody"];
|
||||
};
|
||||
"cabana.FieldNotice": {
|
||||
field: string;
|
||||
locale?: string;
|
||||
message: string;
|
||||
};
|
||||
"cabana.FieldPreset": {
|
||||
field: string;
|
||||
type: string;
|
||||
};
|
||||
"cabana.FieldTypeAssets": {
|
||||
element: string;
|
||||
name: string;
|
||||
scripts: string[];
|
||||
styles: string[];
|
||||
translatable: boolean;
|
||||
};
|
||||
"cabana.FieldTypesResponse": {
|
||||
data: components["schemas"]["cabana.FieldTypeAssets"][];
|
||||
meta: components["schemas"]["cabana.SuccessMeta"];
|
||||
};
|
||||
"cabana.FileItem": {
|
||||
content_type: string;
|
||||
created_at: string;
|
||||
@@ -4736,6 +4821,11 @@ export interface components {
|
||||
*/
|
||||
deferrable?: boolean;
|
||||
displayFormat?: string;
|
||||
/**
|
||||
* @description Element is the custom-element tag of a field whose type a plugin
|
||||
* registers (pact.HasFormFieldTypes); the admin renders it for the field.
|
||||
*/
|
||||
element?: string;
|
||||
emptyOption?: string;
|
||||
/** @description FileTypes are the allowed lower-case extensions of a fileupload field. */
|
||||
fileTypes?: string[];
|
||||
@@ -4812,9 +4902,21 @@ export interface components {
|
||||
tab?: string;
|
||||
/** @description ThumbOptions carries the preview thumbnail mode. */
|
||||
thumbOptions?: components["schemas"]["cabana.ThumbOptions"];
|
||||
/**
|
||||
* @description Translatable is true when a plugin field type's value is a map of
|
||||
* content locale to string.
|
||||
*/
|
||||
translatable?: boolean;
|
||||
/** @description TwelveHour shows a 12-hour clock. */
|
||||
twelveHour?: boolean;
|
||||
type: string;
|
||||
/**
|
||||
* @description TypeOptions are a plugin field type's own fields.yaml keys and values;
|
||||
* the admin hands them to the element as JSON.
|
||||
*/
|
||||
typeOptions?: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
/** @description UseCaption lets the admin edit each file's title and description. */
|
||||
useCaption?: boolean;
|
||||
/** @description Widget is the custom-element tag of a `type: widget` field (D-06). */
|
||||
@@ -5025,6 +5127,7 @@ export interface components {
|
||||
labels: {
|
||||
[key: string]: components["schemas"]["cabana.RelationOption"][];
|
||||
};
|
||||
notices?: components["schemas"]["cabana.FieldNotice"][];
|
||||
};
|
||||
"cabana.RelationColumn": {
|
||||
key: string;
|
||||
|
||||
Reference in New Issue
Block a user