feat(12.1-02): read-only preview screen with a status hint and record actions

- config_form.yaml preview block (optional headerPartial), reported in the form schema as preview
- fields with context: preview show only on the preview screen and are never written
- form messages preview and edit; recordActions without a preview block stops boot
- SPA route {id}/preview, PreviewView and PreviewField, record actions in the footer
- mapWinterUrl maps preview/:id; the update form returns to the preview
- summer-callout partial style classes for status hints
- README, docs, OpenAPI document, TS types and the embedded build updated
This commit is contained in:
Jakub Zych
2026-10-05 00:10:48 +02:00
parent 1c99de5013
commit a65c670574
50 changed files with 1441 additions and 66 deletions

View File

@@ -62,6 +62,12 @@
},
"deleted": {
"other": "Gadget deleted"
},
"preview": {
"other": "Record preview"
},
"edit": {
"other": "Edit record"
}
},
"meta": {

View File

@@ -47,6 +47,12 @@
},
"deleted": {
"other": "Widget deleted"
},
"preview": {
"other": "Record preview"
},
"edit": {
"other": "Edit record"
}
},
"meta": {

View File

@@ -0,0 +1,29 @@
{
"data": {
"name": "Person",
"modelClass": "Person",
"fields": [
{ "name": "name", "type": "text", "label": "Name", "span": "left" },
{ "name": "email", "type": "text", "label": "Email", "span": "right" },
{ "name": "joined_ip", "type": "text", "label": "Joined from IP address", "context": "preview" }
],
"preview": { "headerPartial": "status" },
"messages": {
"create": { "other": "Person" },
"update": { "other": "Edit record" },
"saved": { "other": "Saved" },
"deleteConfirm": { "other": "Delete this record?" },
"deleted": { "other": "Record deleted" },
"preview": { "other": "Person details" },
"edit": { "other": "Edit person" }
},
"redirects": {
"default": "acme/roster/people",
"create": { "redirect": "acme/roster/people/preview/:id", "redirectClose": "acme/roster/people" },
"update": { "redirect": "acme/roster/people", "redirectClose": "acme/roster/people/preview/:id" }
},
"meta": { "locale": "en" },
"assets": { "scripts": [], "styles": [] }
},
"meta": { "locale": "en" }
}

View File

@@ -8,7 +8,7 @@
"showCheckboxes": true,
"showSorting": true,
"searchTerm": "search",
"recordUrl": "acme/roster/people/update/:id",
"recordUrl": "acme/roster/people/preview/:id",
"toolbarButtons": ["create", "delete"],
"toolbarActions": [],
"assets": { "scripts": [], "styles": [] },

View File

@@ -1,5 +1,5 @@
{
"data": { "id": 1, "name": "Ada Lovelace", "email": "ada@example.test" },
"data": { "id": 1, "name": "Ada Lovelace", "email": "ada@example.test", "joined_ip": "203.0.113.7" },
"meta": {
"labels": {},
"actions": [

View File

@@ -70,6 +70,12 @@
},
"deleted": {
"other": "Deleted"
},
"preview": {
"other": "Record preview"
},
"edit": {
"other": "Edit record"
}
},
"meta": {

View File

@@ -18,6 +18,7 @@ import listJson from './widgets.list.json'
import listSchemaJson from './widgets.list-schema.json'
import optionsJson from './widgets.options.json'
import rosterListJson from './roster.list.json'
import rosterFormSchemaJson from './roster.form-schema.json'
import rosterListSchemaJson from './roster.list-schema.json'
import rosterRecordJson from './roster.record.json'
import recordJson from './widgets.record.json'
@@ -59,6 +60,8 @@ export const extensionPartialFixture = extensionPartialJson as S['cabana.Envelop
export const listFixture: Rows = listJson
/** A people list with declared bulk actions (Phase 12.1). */
export const rosterListSchemaFixture: S['cabana.Envelope-cabana_ListSchema'] = rosterListSchemaJson
/** The people form: a preview block with a status hint and a preview-only field (Phase 12.1). */
export const rosterFormSchemaFixture: S['cabana.Envelope-cabana_FormView'] = rosterFormSchemaJson
/** One person with two offered record actions (Phase 12.1). */
export const rosterRecordFixture: S['cabana.RecordEnvelope'] = rosterRecordJson
/** The people of the roster list (Phase 12.1). */

View File

@@ -138,6 +138,12 @@
},
"deleted": {
"other": "Widget deleted"
},
"preview": {
"other": "Record preview"
},
"edit": {
"other": "Edit record"
}
},
"meta": {