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

@@ -92,6 +92,10 @@ func compileExtension(pluginID string, cc *CompiledController, fsys fs.FS) error
if formFile == "" {
formFile = "config_form.yaml"
}
// Record actions are offered on the preview screen only (D-10, D-11).
if len(cc.Form.recordActions) > 0 && cc.Form.preview == nil {
return bootErr(pluginID, id, formFile, fmt.Errorf("recordActions needs a preview block (record actions are offered on the preview screen)"))
}
for _, name := range cc.Form.recordActions {
action, ok := recordActions[name]
if !ok {
@@ -144,8 +148,10 @@ func compileExtension(pluginID string, cc *CompiledController, fsys fs.FS) error
}
// compilePartials reads and parses every partial the controller declares:
// config_list.yaml headerPartial and each `type: partial` field's path, both
// resolving to {ConfigDir}/_{name}.htm. A missing or unparsable template, or a
// config_list.yaml headerPartial, config_form.yaml preview.headerPartial and
// each `type: partial` field's path, all resolving to {ConfigDir}/_{name}.htm.
// The preview header partial is a form partial: the partial route renders it
// with a record id, loaded through the form scope. A missing or unparsable template, or a
// controller without pact.AdminPartialData, fails boot (D-11).
func compilePartials(pluginID string, cc *CompiledController, fsys fs.FS) error {
id := cc.Controller.ID()
@@ -155,6 +161,10 @@ func compilePartials(pluginID string, cc *CompiledController, fsys fs.FS) error
names = append(names, cc.List.HeaderPartial)
}
if cc.Form != nil {
if cc.Form.preview != nil && cc.Form.preview.HeaderPartial != "" {
names = append(names, cc.Form.preview.HeaderPartial)
formNames[cc.Form.preview.HeaderPartial] = true
}
for _, field := range cc.Form.Fields {
if field.Type == "partial" {
names = append(names, field.Path)