Skip to content

Commit e412fb6

Browse files
os-zhuangclaude
andauthored
feat(approvals): declare file attachments on approve/reject decisions (#3332)
* feat(approvals): declare file attachments on approve/reject decisions 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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ypkQikZ55oWUHUnMebwXA * chore(changeset): plugin-approvals decision attachments Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ypkQikZ55oWUHUnMebwXA --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e32bec7 commit e412fb6

3 files changed

Lines changed: 31 additions & 0 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
"@objectstack/plugin-approvals": minor
3+
---
4+
5+
feat(approvals): declare file attachments on approve/reject decisions
6+
7+
The declared `approval_approve` / `approval_reject` actions on
8+
`sys_approval_request` gain an optional multi-file `attachments` param
9+
(`type: 'file'`, `multiple`). The console renders `type:'file'` action params
10+
through the shared upload widget (objectui ADR-0059) and POSTs the resolved
11+
`attachments: string[]`, so a reviewer can attach supporting files to a
12+
decision through the generic declared-action dialog — letting the approvals
13+
inbox retire its hand-wired attachment composer (objectui#2698).
14+
15+
Purely additive metadata: the decision route already forwards
16+
`body.attachments` to `ApprovalService.decide`, and the
17+
`sys_approval_action.attachments` column (file, multiple) already persists them
18+
(#3266/#3274). No service or route change.

packages/plugins/plugin-approvals/src/sys-approval-request.object.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,12 @@ describe('sys_approval_request declared actions', () => {
9191
expect(c.required ?? false).toBe(false);
9292
}
9393
});
94+
95+
it('approve/reject collect optional multi-file decision attachments', () => {
96+
for (const name of ['approval_approve', 'approval_reject']) {
97+
const att = byName(name).params.find((p: any) => p.name === 'attachments');
98+
expect(att, `${name}.attachments`).toMatchObject({ type: 'file', multiple: true });
99+
expect(att.required ?? false).toBe(false);
100+
}
101+
});
94102
});

packages/plugins/plugin-approvals/src/sys-approval-request.object.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ export const SysApprovalRequest = ObjectSchema.create({
248248
target: '/api/v1/approvals/requests/{id}/approve',
249249
params: [
250250
{ name: 'comment', label: 'Comment', type: 'textarea', required: false },
251+
// Decision attachments (#3266). The console renders `type:'file'` params
252+
// through the shared upload widget and POSTs the resolved `attachments:
253+
// string[]`; the decision route persists them on `sys_approval_action`.
254+
{ name: 'attachments', label: 'Attachments', type: 'file', multiple: true, required: false },
251255
],
252256
visible: 'record.status == "pending"',
253257
locations: ['record_section', 'list_item'],
@@ -263,6 +267,7 @@ export const SysApprovalRequest = ObjectSchema.create({
263267
target: '/api/v1/approvals/requests/{id}/reject',
264268
params: [
265269
{ name: 'comment', label: 'Comment', type: 'textarea', required: false },
270+
{ name: 'attachments', label: 'Attachments', type: 'file', multiple: true, required: false },
266271
],
267272
visible: 'record.status == "pending"',
268273
confirmText: 'Reject this request? A rejection is final for every approver.',

0 commit comments

Comments
 (0)