feat(cabana): widget action payload and data channel (quick-261006-eyj)

- pact.AdminActionInput.Payload (json.RawMessage) carries the widget's own
  JSON value untouched; pact.AdminActionResult.Data is passed through as data
- cabana decodes payload with a 64 KiB cap (422 on body), refuses it on the
  toolbar and record routes, and embeds Data once encoded with a 256 KiB cap
  (opaque 500 when larger or unencodable); fill stays filtered
- root .swaggo overrides json.RawMessage so swag keeps record_id and values;
  admin.json and schema.d.ts regenerated (payload?: unknown, data?: unknown)
- TestWidgetPayloadAndData covers pass-through, cap, refusal and data 500
- cabana and pact READMEs, partials-and-widgets and admin-spa docs updated
This commit is contained in:
Jakub Zych
2026-10-06 11:13:16 +02:00
parent 964145628a
commit 6af88f9df6
12 changed files with 257 additions and 32 deletions

View File

@@ -135,6 +135,29 @@ func (c actController) AdminActions() []pact.AdminAction {
Name: "lookup", Label: "acme.demo::lang.gadgets.lookup", Permissions: []string{"acme.demo.run"},
Run: func(_ context.Context, in pact.AdminActionInput) (pact.AdminActionResult, error) {
c.spy.record(in)
if len(in.Payload) > 0 {
// The payload round trip: echo the decoded payload as data
// next to a fill that must still be filtered; "big" and
// "nan" answer data the framework must reject.
var payload any
if err := json.Unmarshal(in.Payload, &payload); err != nil {
return pact.AdminActionResult{}, err
}
switch payload {
case "big":
return pact.AdminActionResult{Data: strings.Repeat("x", 256<<10+1)}, nil
case "nan":
return pact.AdminActionResult{Data: math.NaN()}, nil
}
return pact.AdminActionResult{
Message: "acme.demo::lang.gadgets.looked_up",
Fill: map[string]any{"name": "reordered", "tenant": "other", "active": []string{"a"}},
Data: map[string]any{
"echo": payload,
"items": []map[string]any{{"id": 1, "title": "a"}},
},
}, nil
}
switch in.Values["name"] {
case "invalid":
return pact.AdminActionResult{}, &cabana.ValidationError{Details: map[string]any{"name": []string{"Name is taken."}}}