-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathdynamic-approval.flow.ts
More file actions
70 lines (68 loc) · 2.72 KB
/
Copy pathdynamic-approval.flow.ts
File metadata and controls
70 lines (68 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
import { defineFlow } from '@objectstack/spec';
/**
* #3447 P2 dogfood: dynamic approver routing end to end.
*
* Two-stage approval where the FIRST approver picks the second stage's
* approvers in their decision (`decisionOutputs`), and the second stage
* resolves them at node entry from an `expression` approver over `vars.*` —
* no record-field detour. Trigger: retitling an announcement (an otherwise
* approval-free object, so this demo never collides with the expense/invoice/
* project approval flows — the service dedupes pending requests per record).
*/
export const DynamicApprovalFlow = defineFlow({
name: 'showcase_dynamic_approval',
label: 'Announcement Dynamic Approval',
description: 'Lead reviewer picks the co-signers in their decision; the co-sign step resolves them at entry.',
type: 'autolaunched',
status: 'active',
nodes: [
{
id: 'start',
type: 'start',
label: 'On Announcement Retitled',
config: {
objectName: 'showcase_announcement',
triggerType: 'record-after-update',
condition: 'title != previous.title',
},
},
{
id: 'lead_review',
type: 'approval',
label: 'Lead Review',
config: {
// The seeded admin holds the org-membership `owner` tier, so the demo
// routes stage 1 to them without hard-coding a user id.
approvers: [{ type: 'org_membership_level', value: 'owner' }],
behavior: 'first_response',
lockRecord: true,
// The lead hands the co-signers to the flow with their decision. The
// TYPED declaration renders a multi-select sys_user picker in the
// decision dialog (bare string keys render free text).
decisionOutputs: [{ key: 'next_reviewers', label: 'Next Reviewers', type: 'user', multiple: true }],
},
},
{
id: 'co_sign',
type: 'approval',
label: 'Co-sign',
config: {
// Resolved at node entry from the lead's decision outputs (#3447 P2).
approvers: [{ type: 'expression', value: 'vars.lead_review.next_reviewers' }],
behavior: 'unanimous',
lockRecord: true,
onEmptyApprovers: 'fail',
},
},
{ id: 'approved', type: 'end', label: 'Approved' },
{ id: 'rejected', type: 'end', label: 'Rejected' },
],
edges: [
{ id: 'e1', source: 'start', target: 'lead_review' },
{ id: 'e2', source: 'lead_review', target: 'co_sign', label: 'approve' },
{ id: 'e3', source: 'lead_review', target: 'rejected', label: 'reject' },
{ id: 'e4', source: 'co_sign', target: 'approved', label: 'approve' },
{ id: 'e5', source: 'co_sign', target: 'rejected', label: 'reject' },
],
});