@@ -10,13 +10,37 @@ const task = 'showcase_task';
1010 * record header/more, related list, global nav).
1111 */
1212
13- /** script — inline handler, shown on each row and the record header. */
13+ /**
14+ * script — inline sandboxed handler, shown on each row and the record header.
15+ *
16+ * The `body` (L2 sandboxed JS) is what makes this action *executable*: AppPlugin
17+ * walks the bundle's actions on bind and only registers an engine handler for
18+ * those carrying a `body` (or `target` -> bundle function). Without it the
19+ * runtime has nothing to invoke and `POST /actions/showcase_task/showcase_mark_done`
20+ * fails with "Action ... not found".
21+ *
22+ * It flips the dedicated `done` flag and `progress` rather than the `status`
23+ * select on purpose: `status` is governed by the `task_status_flow`
24+ * state-machine (only `in_review -> done` is a legal direct jump), so writing
25+ * `status: 'done'` from a Backlog/To Do/In Progress row would be rejected. The
26+ * `done` boolean is the completion flag that works from any state.
27+ */
1428export const MarkDoneAction = defineAction ( {
1529 name : 'showcase_mark_done' ,
1630 label : 'Mark Done' ,
1731 icon : 'check' ,
1832 objectName : task ,
1933 type : 'script' ,
34+ body : {
35+ language : 'js' ,
36+ source :
37+ "var id = ctx.recordId || (ctx.record && ctx.record.id) || input.recordId;" +
38+ "if (!id) throw new Error('No record to mark done');" +
39+ "await ctx.api.object('showcase_task').update({ id: id, done: true, progress: 100 });" +
40+ "return { ok: true, id: id };" ,
41+ capabilities : [ 'api.write' ] ,
42+ } ,
43+ successMessage : 'Task marked done.' ,
2044 // `record_section` so the Task Detail page's `record:quick_actions` bar
2145 // (which names this action) resolves it — the engine location-filters even
2246 // explicitly-named actions, mirroring the platform's own sys-user pages.
0 commit comments