Commit Graph

16 Commits

Author SHA1 Message Date
23f33c3911 feat(17-01): tree reorder page and singleton admin controllers
- cabana: config_reorder.yaml (title, nameFrom, modelClass, parentColumn,
  sortColumn, maxDepth, partition) with fail-loud boot checks and the
  built-in reorder toolbar button; list schema carries reorder
- GET/POST {controller}/reorder: scoped set (ListExtendQuery plus the
  partition) locked FOR UPDATE, 409 reorder_stale on any set difference,
  422 for duplicates, foreign parents, cycles and maxDepth, both columns
  written without model hooks
- pact.AdminSingleton: GET {controller}/singleton (first or create, form
  scope checked), form schema singleton, list/create/bulk/delete 404,
  no config_list.yaml needed
- swag, inventories, token classes, CSRF walk, conformance cases, backend
  lang reorder.stale and load_failed, reorder and singleton smoke tests, docs
2026-10-12 15:35:43 +02:00
e24e03c47d feat(16.3-01): admin:token CLI, party.Activated, READMEs and docs
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-11 01:55:07 +02:00
183583e0e9 feat(16.3-01): interactive-only gates, ResolveBackend, last_used stamp
- Refuse g15_ tokens on account/avatar/refresh/logout; gate field-types and markdown
- Publish cookie-less ResolveBackend; debounce last_used_at once per minute
- Reserve account vendor segment; TestTokenGatesSmoke covers the deny path

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-11 01:47:52 +02:00
8fa92db96d feat(16.2-01): translatable plugin field types, untouched skip, writes, list values and uploads
- translatable types lift, store and hydrate through the ML path
  (isMLField); Decode and Load run per locale and notices carry the locale
- on update a value equal to the served value (Load of the stored host
  value or exact translation) is neither decoded nor written
- FieldWrite, FieldWritesFromContext and WithFieldWrites expose what a save
  writes to the Form hooks
- list columns may use a plugin alias and show the type's ListValue
- POST .../{id}/fields/{field}/upload hands the file to the type's Upload
  (guard, X-Requested-With, permissions, field context, record scope, body
  cap); OpenAPI, route inventories, README and docs updated
2026-10-10 11:19:24 +02:00
717d46ec3d 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
2026-10-10 11:06:12 +02:00
Jakub Zych
4a9b0896b1 feat(cabana): settings entries that link to an admin controller
pact.SettingsItem gains an additive Controller field, the equivalent of a
WinterCMS registerSettings 'url' => Backend::url(...) entry. A link entry
declares no Model, Form or NewModel and needs no AdminFS; start-up fails
when it combines Controller with a singleton form or a model, or names an
unregistered controller. Settings codes stay one namespace.

GET /settings lists a link entry with its controller only when the
principal passes the item's permissions and may open the controller.
Registry.Setting never returns a link entry, so the singleton settings
endpoints answer 404 for its code. SettingsEntry carries controller,
empty for singletons; the OpenAPI document, generated SPA types and
settings fixture follow, and the pact and cabana READMEs and the
settings docs describe the link.
2026-10-07 18:22:01 +02:00
Jakub Zych
f50d9b8f10 feat(12.1-02): permissioneditor field in radio or checkbox mode
- type: permissioneditor with mode radio (1, -1) or checkbox (1); the
  controller serves the options per request through
  cabana.PermissionEditorProvider and reads and stores the values
- a save answers 422 for a non-object, an unknown code or a value outside the
  mode's set and 403 for a changed locked code; stored codes that are not
  offered are kept
- record responses carry the stored permissions as an object
- SPA: PermissionEditorField with sections by tab, locked rows and a read-only
  mode for the preview
- README, docs, OpenAPI document, TS types and dist updated
2026-10-05 10:44:50 +02:00
Jakub Zych
e0ccced76a feat(12.1-01): declared record actions with an applicability rule
- pact.HasAdminRecordActions with AdminRecordAction (Applies, Run)
- config_form.yaml recordActions, compiled fail-loud
- show response meta.actions lists the permitted actions that apply
- POST .../{controller}/{id}/actions/{action}: record loaded and locked
  through the form scope; 404 out of scope, 409 when it does not apply
- RecordActions.vue with confirm and request flow (mounted by plan 02)
- roster fixture, smoke tests, OpenAPI, TS types, READMEs, docs
2026-10-04 23:37:30 +02:00
Jakub Zych
a879d6388c feat(12.1-01): declared bulk actions on admin lists
- pact.HasAdminBulkActions with AdminBulkAction, its input and result
- config_list.yaml bulkActions, compiled fail-loud, needs showCheckboxes
- POST .../{controller}/bulk/{action}: ids resolved and locked through the
  list scope in one transaction; partial selection is 409
- list schema offers declared actions per principal, with confirm text
- admin SPA bulk actions menu with confirm, busy state and failure toasts
- acme.roster fixture, tracer test, OpenAPI, TS types, dist, READMEs, docs
2026-10-04 23:28:30 +02:00
Jakub Zych
fe9e8baaf1 feat(12.2-03): defer relation work on unsaved records and add child file routes
- record id 0 with X-Session-Key manages deferrable relations: create, link, unlink, delete and pivot edits are held in deferred_bindings
- the record's create save applies relation bindings with the file bindings; an ineligible link is a 422 on the relation-manager field
- child forms upload files through .../records/{child}/files/{field} keyed by X-Child-Session-Key; the child save commits them
- boot refuses a deferrable relation with create whose related model no plugin lists in Models()
2026-10-02 19:08:16 +02:00
Jakub Zych
67d4c7ff13 feat(12.2-02): add the datepicker field with server-side bounds and date list columns
- type: datepicker compiles the D-20 keys; format maps to displayFormat with WinterCMS's momentFormat table
- boot fails when the mode does not match the column's Go type (time.Time, lagoon.Date, lagoon.TimeOfDay)
- datepicker is a writable scalar field; minDate and maxDate are rechecked on save
- columns.yaml accepts type: date and type: time; Scanner/Valuer structs are columns, not relations
- conformance fixture carries date and datetime fields; README, forms and lists docs
2026-10-02 18:19:04 +02:00
Jakub Zych
044e0450ef feat(12.2-02): add the fileupload field with deferred uploads committed on save
- type: fileupload compiles the D-08 keys and binds to the model's attach.Relation at boot
- X-Session-Key (cabana.SessionKeyHeader) carries the form session key; RecordInput.SessionKey
- GET and POST .../{id}/files/{field}: list with pending uploads, multipart upload into attach.Store
- the create and update save attaches the session's pending files in its transaction
- swagger2openapi folds formData parameters into a multipart requestBody
- admin OpenAPI, TS types, conformance cases, README and forms docs
2026-10-02 18:04:34 +02:00
Jakub Zych
f2ab93f291 fix(09): WR-03 refuse writes that the compiled list and form do not declare 2026-10-01 21:04:31 +02:00
Jakub Zych
8b1cb244de feat(10.1-01): serve controller JS/CSS and run registered toolbar actions
- boardwalk exports ContentType and SetSecurityHeaders
- pact.AdminClientAssets files are read and hashed at boot and served by exact
  key under {prefix}/assets/{vendor}/{plugin}/ with nosniff, CSP, CORP,
  no-cache and an ETag; a miss falls through to the SPA
- list and form schemas carry assets URLs with a ?v= hash
- toolbar.buttons resolves create, delete and registered actions after decode;
  toolbarActions is permission-filtered per admin
- POST .../toolbar/{action} behind requireAjax and action permissions
2026-09-28 23:41:17 +02:00
Jakub Zych
f9281949a6 feat(10.1-01): run registered widget actions through a cabana-owned route
- pact: AdminClientAssets, AdminAction, AdminActionInput, AdminActionResult,
  HasAdminActions and AdminPartialData contracts
- fields.yaml type: widget with widget, action and fill keys; boot checks the
  plugin tag prefix, the registered action and writable scalar fill fields
- POST .../widgets/{field} behind requireAjax, controller and action
  permissions, scoped non-locking record read and a server-side fill filter
- typed OpenAPI operation, inventories and an acme conformance case
2026-09-28 23:35:00 +02:00
Jakub Zych
5e50b166ef refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
2026-09-28 02:21:02 +02:00