From dd3050c799db43e441e7932149d680d2048ca004 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 01:55:42 +0000 Subject: [PATCH 1/2] feat(approvals): declare file attachments on approve/reject decisions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional multi-file `attachments` param to the declared `approval_approve` / `approval_reject` actions on sys_approval_request. The console now renders `type:'file'` action params through the shared upload widget (objectui ADR-0059) and POSTs the resolved `attachments: string[]`, so a reviewer can attach supporting files to a decision through the generic declared-action dialog — no bespoke composer. No service/route change: the decision route already forwards `body.attachments` to `ApprovalService.decide`, and the `sys_approval_action.attachments` column (file, multiple) already persists them (#3266/#3274). This just surfaces the capability as declared metadata so the approvals inbox can retire its hand-wired attachment composer (objectui#2698). Contract test pins the new param (type file, multiple, optional). Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_016ypkQikZ55oWUHUnMebwXA --- .../src/sys-approval-request.object.test.ts | 8 ++++++++ .../plugin-approvals/src/sys-approval-request.object.ts | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/packages/plugins/plugin-approvals/src/sys-approval-request.object.test.ts b/packages/plugins/plugin-approvals/src/sys-approval-request.object.test.ts index 4dbb5c52f4..e293ea90d9 100644 --- a/packages/plugins/plugin-approvals/src/sys-approval-request.object.test.ts +++ b/packages/plugins/plugin-approvals/src/sys-approval-request.object.test.ts @@ -91,4 +91,12 @@ describe('sys_approval_request declared actions', () => { expect(c.required ?? false).toBe(false); } }); + + it('approve/reject collect optional multi-file decision attachments', () => { + for (const name of ['approval_approve', 'approval_reject']) { + const att = byName(name).params.find((p: any) => p.name === 'attachments'); + expect(att, `${name}.attachments`).toMatchObject({ type: 'file', multiple: true }); + expect(att.required ?? false).toBe(false); + } + }); }); diff --git a/packages/plugins/plugin-approvals/src/sys-approval-request.object.ts b/packages/plugins/plugin-approvals/src/sys-approval-request.object.ts index 617c49ff68..2b0d55e03e 100644 --- a/packages/plugins/plugin-approvals/src/sys-approval-request.object.ts +++ b/packages/plugins/plugin-approvals/src/sys-approval-request.object.ts @@ -248,6 +248,10 @@ export const SysApprovalRequest = ObjectSchema.create({ target: '/api/v1/approvals/requests/{id}/approve', params: [ { name: 'comment', label: 'Comment', type: 'textarea', required: false }, + // Decision attachments (#3266). The console renders `type:'file'` params + // through the shared upload widget and POSTs the resolved `attachments: + // string[]`; the decision route persists them on `sys_approval_action`. + { name: 'attachments', label: 'Attachments', type: 'file', multiple: true, required: false }, ], visible: 'record.status == "pending"', locations: ['record_section', 'list_item'], @@ -263,6 +267,7 @@ export const SysApprovalRequest = ObjectSchema.create({ target: '/api/v1/approvals/requests/{id}/reject', params: [ { name: 'comment', label: 'Comment', type: 'textarea', required: false }, + { name: 'attachments', label: 'Attachments', type: 'file', multiple: true, required: false }, ], visible: 'record.status == "pending"', confirmText: 'Reject this request? A rejection is final for every approver.', From d2adc9545994f00405a70f0f6321215beb003b8f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Jul 2026 01:59:42 +0000 Subject: [PATCH 2/2] chore(changeset): plugin-approvals decision attachments Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_016ypkQikZ55oWUHUnMebwXA --- .changeset/approvals-decision-attachments.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .changeset/approvals-decision-attachments.md diff --git a/.changeset/approvals-decision-attachments.md b/.changeset/approvals-decision-attachments.md new file mode 100644 index 0000000000..39ee142bc6 --- /dev/null +++ b/.changeset/approvals-decision-attachments.md @@ -0,0 +1,18 @@ +--- +"@objectstack/plugin-approvals": minor +--- + +feat(approvals): declare file attachments on approve/reject decisions + +The declared `approval_approve` / `approval_reject` actions on +`sys_approval_request` gain an optional multi-file `attachments` param +(`type: 'file'`, `multiple`). The console renders `type:'file'` action params +through the shared upload widget (objectui ADR-0059) and POSTs the resolved +`attachments: string[]`, so a reviewer can attach supporting files to a +decision through the generic declared-action dialog — letting the approvals +inbox retire its hand-wired attachment composer (objectui#2698). + +Purely additive metadata: the decision route already forwards +`body.attachments` to `ApprovalService.decide`, and the +`sys_approval_action.attachments` column (file, multiple) already persists them +(#3266/#3274). No service or route change.