hap-cli 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hap_cli/README.md +194 -0
- hap_cli/README_CN.md +601 -0
- hap_cli/__init__.py +3 -0
- hap_cli/commands/__init__.py +1 -0
- hap_cli/commands/ai_cmd.py +224 -0
- hap_cli/commands/app_cmd.py +308 -0
- hap_cli/commands/calendar_cmd.py +138 -0
- hap_cli/commands/chat_cmd.py +101 -0
- hap_cli/commands/config_cmd.py +169 -0
- hap_cli/commands/contact_cmd.py +125 -0
- hap_cli/commands/department_cmd.py +168 -0
- hap_cli/commands/group_cmd.py +128 -0
- hap_cli/commands/instance_cmd.py +310 -0
- hap_cli/commands/node_cmd.py +538 -0
- hap_cli/commands/optionset_cmd.py +99 -0
- hap_cli/commands/page_cmd.py +102 -0
- hap_cli/commands/plugin_cmd.py +133 -0
- hap_cli/commands/post_cmd.py +155 -0
- hap_cli/commands/record_cmd.py +228 -0
- hap_cli/commands/role_cmd.py +221 -0
- hap_cli/commands/workflow_cmd.py +284 -0
- hap_cli/commands/worksheet_cmd.py +342 -0
- hap_cli/context.py +43 -0
- hap_cli/core/__init__.py +1 -0
- hap_cli/core/ai.py +133 -0
- hap_cli/core/app.py +307 -0
- hap_cli/core/auth.py +219 -0
- hap_cli/core/calendar_mod.py +114 -0
- hap_cli/core/chat.py +73 -0
- hap_cli/core/contact.py +85 -0
- hap_cli/core/department.py +131 -0
- hap_cli/core/flow_node.py +1001 -0
- hap_cli/core/group.py +99 -0
- hap_cli/core/instance.py +572 -0
- hap_cli/core/optionset.py +112 -0
- hap_cli/core/page.py +138 -0
- hap_cli/core/plugin.py +87 -0
- hap_cli/core/post.py +118 -0
- hap_cli/core/record.py +268 -0
- hap_cli/core/role.py +227 -0
- hap_cli/core/session.py +348 -0
- hap_cli/core/workflow.py +556 -0
- hap_cli/core/worksheet.py +403 -0
- hap_cli/hap_cli.py +105 -0
- hap_cli/skills/SKILL.md +383 -0
- hap_cli/skills/__init__.py +0 -0
- hap_cli/tests/__init__.py +1 -0
- hap_cli/tests/test_core.py +1824 -0
- hap_cli/tests/test_full_e2e.py +136 -0
- hap_cli/tests/test_integration.py +805 -0
- hap_cli/utils/__init__.py +1 -0
- hap_cli/utils/formatting.py +111 -0
- hap_cli/utils/options.py +10 -0
- hap_cli-0.5.0.dist-info/METADATA +223 -0
- hap_cli-0.5.0.dist-info/RECORD +58 -0
- hap_cli-0.5.0.dist-info/WHEEL +5 -0
- hap_cli-0.5.0.dist-info/entry_points.txt +2 -0
- hap_cli-0.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1001 @@
|
|
|
1
|
+
"""Workflow node management for MingDAO HAP.
|
|
2
|
+
|
|
3
|
+
Covers: add/delete/get nodes, save node config, update node name/desc,
|
|
4
|
+
data processing nodes (create/update/delete/search records),
|
|
5
|
+
code test, webhook test, AIGC test, code templates, and JSON-to-controls.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Optional
|
|
9
|
+
|
|
10
|
+
from hap_cli.core.session import Session
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# ── Node Type Constants ──────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
NODE_TYPE = {
|
|
16
|
+
"START": 0,
|
|
17
|
+
"BRANCH": 1,
|
|
18
|
+
"BRANCH_ITEM": 2,
|
|
19
|
+
"FILL": 3,
|
|
20
|
+
"APPROVAL": 4,
|
|
21
|
+
"CC": 5,
|
|
22
|
+
"ACTION": 6, # Data processing: add/edit/delete record
|
|
23
|
+
"SEARCH": 7, # Get single record
|
|
24
|
+
"WEBHOOK": 8,
|
|
25
|
+
"FORMULA": 9,
|
|
26
|
+
"MESSAGE": 10,
|
|
27
|
+
"EMAIL": 11,
|
|
28
|
+
"DELAY": 12,
|
|
29
|
+
"GET_MORE_RECORD": 13, # Get multiple records / batch ops
|
|
30
|
+
"CODE": 14,
|
|
31
|
+
"LINK": 15,
|
|
32
|
+
"SUB_PROCESS": 16,
|
|
33
|
+
"PUSH": 17,
|
|
34
|
+
"FILE": 18,
|
|
35
|
+
"TEMPLATE": 19,
|
|
36
|
+
"PBP": 20,
|
|
37
|
+
"JSON_PARSE": 21,
|
|
38
|
+
"AUTHENTICATION": 22,
|
|
39
|
+
"PARAMETER": 23,
|
|
40
|
+
"API_PACKAGE": 24,
|
|
41
|
+
"API": 25,
|
|
42
|
+
"APPROVAL_PROCESS": 26,
|
|
43
|
+
"NOTICE": 27,
|
|
44
|
+
"SNAPSHOT": 28,
|
|
45
|
+
"LOOP": 29,
|
|
46
|
+
"RETURN": 30,
|
|
47
|
+
"AIGC": 31,
|
|
48
|
+
"PLUGIN": 32,
|
|
49
|
+
"AGENT": 33,
|
|
50
|
+
"SYSTEM": 100,
|
|
51
|
+
"TOOLS": 101,
|
|
52
|
+
"FIND_SINGLE_MESSAGE": 1000,
|
|
53
|
+
"FIND_MORE_MESSAGE": 1001,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# ── Action ID Constants (for ACTION / SEARCH / GET_MORE_RECORD) ──────────
|
|
57
|
+
|
|
58
|
+
ACTION_ID = {
|
|
59
|
+
# ACTION node (type 6) operations
|
|
60
|
+
"ADD_RECORD": "1",
|
|
61
|
+
"EDIT_RECORD": "2",
|
|
62
|
+
"DELETE_RECORD": "3",
|
|
63
|
+
"CREATE_FILE": "4",
|
|
64
|
+
"CREATE_RECORD": "5",
|
|
65
|
+
"REFRESH_SINGLE_DATA": "6",
|
|
66
|
+
"REFUND": "7",
|
|
67
|
+
"RELATION": "20",
|
|
68
|
+
# FORMULA node (type 9) operations
|
|
69
|
+
"NUMBER_FORMULA": "100",
|
|
70
|
+
"DATE_FORMULA": "101",
|
|
71
|
+
"JAVASCRIPT": "102",
|
|
72
|
+
"PYTHON": "103",
|
|
73
|
+
"DATE_DIFF_FORMULA": "104",
|
|
74
|
+
"OBJECT_TOTAL": "105",
|
|
75
|
+
"FUNCTION_CALCULATION": "106",
|
|
76
|
+
"WORKSHEET_TOTAL": "107",
|
|
77
|
+
"CUSTOM_ACTION_TOTAL": "108",
|
|
78
|
+
# EMAIL node (type 11) operations
|
|
79
|
+
"SEND_EMAIL_SINGLE_DISPLAY": "201",
|
|
80
|
+
"SEND_EMAIL": "202",
|
|
81
|
+
"SEND_TEMPLATE_MESSAGE": "203",
|
|
82
|
+
# LOOP node (type 29) operations
|
|
83
|
+
"CONDITION_LOOP": "210",
|
|
84
|
+
"COUNT_LOOP": "211",
|
|
85
|
+
# GET_MORE_RECORD node (type 13) operations
|
|
86
|
+
"FROM_WORKSHEET": "400",
|
|
87
|
+
"FROM_RECORD": "401",
|
|
88
|
+
"FROM_ADD": "402",
|
|
89
|
+
"FROM_ARRAY": "403",
|
|
90
|
+
"FROM_CODE_ARRAY": "404",
|
|
91
|
+
"FROM_ARTIFICIAL": "405",
|
|
92
|
+
# SEARCH node (type 7) operations
|
|
93
|
+
"WORKSHEET_FIND": "406",
|
|
94
|
+
"BATCH_FIND": "407",
|
|
95
|
+
"FROM_PBP_INPUT_ARRAY": "408",
|
|
96
|
+
"FROM_API_ARRAY": "409",
|
|
97
|
+
"FROM_PBP_OUTPUT_ARRAY": "410",
|
|
98
|
+
"BATCH_ACTION": "411",
|
|
99
|
+
"BATCH_UPDATE": "412",
|
|
100
|
+
"BATCH_DELETE": "413",
|
|
101
|
+
"FROM_PLUGIN_ARRAY": "414",
|
|
102
|
+
"REFRESH_MULTIPLE_DATA": "415",
|
|
103
|
+
"RECORD_LINK_PAY": "416",
|
|
104
|
+
"RECORD_LINK_FIND": "420",
|
|
105
|
+
"RECORD_UPDATE": "421",
|
|
106
|
+
"RECORD_DELETE": "422",
|
|
107
|
+
# PBP
|
|
108
|
+
"PBP": "500",
|
|
109
|
+
"PBP_INPUT": "501",
|
|
110
|
+
"PBP_OUT": "502",
|
|
111
|
+
# JSON
|
|
112
|
+
"JSON_PARSE": "510",
|
|
113
|
+
"FROM_JSON_PARSE_ARRAY": "511",
|
|
114
|
+
# AUTH
|
|
115
|
+
"NO_AUTH": "520",
|
|
116
|
+
"BASIC_AUTH": "521",
|
|
117
|
+
"AUTH_CODE": "522",
|
|
118
|
+
"CREDENTIALS": "523",
|
|
119
|
+
"REFRESH_CREDENTIALS": "524",
|
|
120
|
+
# AIGC
|
|
121
|
+
"AIGC_TEXT": "531",
|
|
122
|
+
"AIGC_OBJECT": "532",
|
|
123
|
+
"AGENT": "533",
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
APP_TYPE = {
|
|
127
|
+
"SHEET": 1,
|
|
128
|
+
"TASK": 2,
|
|
129
|
+
"LOOP": 5,
|
|
130
|
+
"DATE": 6,
|
|
131
|
+
"WEBHOOK": 7,
|
|
132
|
+
"CUSTOM_ACTION": 8,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# ── Node CRUD ────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def add_node(
|
|
140
|
+
session: Session,
|
|
141
|
+
process_id: str,
|
|
142
|
+
flow_node_type: int,
|
|
143
|
+
name: str = "",
|
|
144
|
+
node_id: str = "",
|
|
145
|
+
select_node_id: str = "",
|
|
146
|
+
action_id: str = "",
|
|
147
|
+
) -> dict[str, Any]:
|
|
148
|
+
"""Add a new node to a workflow.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
session: Active session
|
|
152
|
+
process_id: Process ID
|
|
153
|
+
flow_node_type: Node type (see NODE_TYPE dict)
|
|
154
|
+
name: Node name
|
|
155
|
+
node_id: Explicit node ID (auto-generated if empty)
|
|
156
|
+
select_node_id: Insert after this node
|
|
157
|
+
action_id: Action sub-type (see ACTION_ID dict)
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Created node info
|
|
161
|
+
"""
|
|
162
|
+
data: dict[str, Any] = {
|
|
163
|
+
"processId": process_id,
|
|
164
|
+
"flowNodeType": flow_node_type,
|
|
165
|
+
}
|
|
166
|
+
if name:
|
|
167
|
+
data["name"] = name
|
|
168
|
+
if node_id:
|
|
169
|
+
data["nodeId"] = node_id
|
|
170
|
+
if select_node_id:
|
|
171
|
+
data["selectNodeId"] = select_node_id
|
|
172
|
+
if action_id:
|
|
173
|
+
data["actionId"] = action_id
|
|
174
|
+
return session.workflow_call("flowNode/add", data)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def delete_node(
|
|
178
|
+
session: Session,
|
|
179
|
+
process_id: str,
|
|
180
|
+
node_id: str,
|
|
181
|
+
) -> dict[str, Any]:
|
|
182
|
+
"""Delete a node from a workflow.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
session: Active session
|
|
186
|
+
process_id: Process ID
|
|
187
|
+
node_id: Node ID to delete
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Deletion result
|
|
191
|
+
"""
|
|
192
|
+
return session.workflow_call(
|
|
193
|
+
"flowNode/delete",
|
|
194
|
+
{"processId": process_id, "nodeId": node_id},
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def get_nodes(
|
|
199
|
+
session: Session,
|
|
200
|
+
process_id: str,
|
|
201
|
+
instance_id: str = "",
|
|
202
|
+
) -> dict[str, Any]:
|
|
203
|
+
"""Get all nodes of a workflow.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
session: Active session
|
|
207
|
+
process_id: Process ID
|
|
208
|
+
instance_id: Optional instance ID for runtime view
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Node tree/list
|
|
212
|
+
"""
|
|
213
|
+
data: dict[str, Any] = {"processId": process_id}
|
|
214
|
+
if instance_id:
|
|
215
|
+
data["instanceId"] = instance_id
|
|
216
|
+
return session.workflow_call("flowNode/get", data)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def get_node_detail(
|
|
220
|
+
session: Session,
|
|
221
|
+
process_id: str,
|
|
222
|
+
node_id: str,
|
|
223
|
+
flow_node_type: int = 0,
|
|
224
|
+
select_node_id: str = "",
|
|
225
|
+
app_id: str = "",
|
|
226
|
+
instance_id: str = "",
|
|
227
|
+
) -> dict[str, Any]:
|
|
228
|
+
"""Get detailed configuration of a node.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
session: Active session
|
|
232
|
+
process_id: Process ID
|
|
233
|
+
node_id: Node ID
|
|
234
|
+
flow_node_type: Node type
|
|
235
|
+
select_node_id: Context node
|
|
236
|
+
app_id: App ID
|
|
237
|
+
instance_id: Instance ID (for runtime)
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Node detail dict with full configuration
|
|
241
|
+
"""
|
|
242
|
+
data: dict[str, Any] = {"processId": process_id, "nodeId": node_id}
|
|
243
|
+
if flow_node_type:
|
|
244
|
+
data["flowNodeType"] = flow_node_type
|
|
245
|
+
if select_node_id:
|
|
246
|
+
data["selectNodeId"] = select_node_id
|
|
247
|
+
if app_id:
|
|
248
|
+
data["appId"] = app_id
|
|
249
|
+
if instance_id:
|
|
250
|
+
data["instanceId"] = instance_id
|
|
251
|
+
return session.workflow_call("flowNode/getNodeDetail", data)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
# ── Node Update ──────────────────────────────────────────────────────────
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def update_node_name(
|
|
258
|
+
session: Session,
|
|
259
|
+
process_id: str,
|
|
260
|
+
node_id: str,
|
|
261
|
+
name: str,
|
|
262
|
+
) -> dict[str, Any]:
|
|
263
|
+
"""Update a node's name.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
session: Active session
|
|
267
|
+
process_id: Process ID
|
|
268
|
+
node_id: Node ID
|
|
269
|
+
name: New name
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Update result
|
|
273
|
+
"""
|
|
274
|
+
return session.workflow_call(
|
|
275
|
+
"flowNode/updateFlowNodeName",
|
|
276
|
+
{"processId": process_id, "nodeId": node_id, "name": name},
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def update_node_desc(
|
|
281
|
+
session: Session,
|
|
282
|
+
process_id: str,
|
|
283
|
+
node_id: str,
|
|
284
|
+
desc: str = "",
|
|
285
|
+
alias: str = "",
|
|
286
|
+
) -> dict[str, Any]:
|
|
287
|
+
"""Update a node's description and alias.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
session: Active session
|
|
291
|
+
process_id: Process ID
|
|
292
|
+
node_id: Node ID
|
|
293
|
+
desc: Description
|
|
294
|
+
alias: Node alias
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
Update result
|
|
298
|
+
"""
|
|
299
|
+
data: dict[str, Any] = {"processId": process_id, "nodeId": node_id}
|
|
300
|
+
if desc:
|
|
301
|
+
data["desc"] = desc
|
|
302
|
+
if alias:
|
|
303
|
+
data["alias"] = alias
|
|
304
|
+
return session.workflow_call("flowNode/nodeDesc", data)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def save_node(
|
|
308
|
+
session: Session,
|
|
309
|
+
process_id: str,
|
|
310
|
+
node_id: str,
|
|
311
|
+
flow_node_type: int,
|
|
312
|
+
config: dict[str, Any],
|
|
313
|
+
name: str = "",
|
|
314
|
+
select_node_id: str = "",
|
|
315
|
+
) -> dict[str, Any]:
|
|
316
|
+
"""Save a node's full configuration.
|
|
317
|
+
|
|
318
|
+
This is the universal node save endpoint that supports ALL node types.
|
|
319
|
+
The config dict varies by node type.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
session: Active session
|
|
323
|
+
process_id: Process ID
|
|
324
|
+
node_id: Node ID
|
|
325
|
+
flow_node_type: Node type (see NODE_TYPE dict)
|
|
326
|
+
config: Node-specific configuration dict. Keys vary by type:
|
|
327
|
+
- ACTION(6): actionId, appId, appType, fields, selectNodeId,
|
|
328
|
+
operateCondition, sorts, executeType, filters
|
|
329
|
+
- SEARCH(7): actionId, appId, findFields, executeType, fields,
|
|
330
|
+
operateCondition, sorts, random, filters, link
|
|
331
|
+
- GET_MORE_RECORD(13): actionId, appId, operateCondition, fields,
|
|
332
|
+
selectNodeId, sorts, numberFieldValue, filters
|
|
333
|
+
- FILL(3): formProperties, accounts, submitBtnName, schedule
|
|
334
|
+
- APPROVAL(4): accounts, condition, multipleLevel
|
|
335
|
+
- CC(5): accounts, smsContent, templateId
|
|
336
|
+
- EMAIL(11): accounts, subject, content
|
|
337
|
+
- WEBHOOK(8): url, method, headers, body, contentType
|
|
338
|
+
- CODE(14): code, inputDatas, version, actionId
|
|
339
|
+
- FORMULA(9): actionId, fieldValue, fieldType
|
|
340
|
+
- DELAY(12): time, unit, executeTime
|
|
341
|
+
- SUB_PROCESS(16): subProcessId
|
|
342
|
+
- PUSH(17): pushType, content, appId, viewId, link
|
|
343
|
+
- FILE(18): appId, fileName, pdf
|
|
344
|
+
- JSON_PARSE(21): jsonStr, controls
|
|
345
|
+
- AIGC(31): model, prompt, systemMessage, outputs, actionId
|
|
346
|
+
- LOOP(29): actionId, executeType, numberFieldValue
|
|
347
|
+
- SNAPSHOT(28): appId
|
|
348
|
+
- BRANCH(1/2): operateCondition, resultTypeId
|
|
349
|
+
name: Node name
|
|
350
|
+
select_node_id: Context node
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Save result
|
|
354
|
+
"""
|
|
355
|
+
data: dict[str, Any] = {
|
|
356
|
+
"processId": process_id,
|
|
357
|
+
"nodeId": node_id,
|
|
358
|
+
"flowNodeType": flow_node_type,
|
|
359
|
+
}
|
|
360
|
+
if name:
|
|
361
|
+
data["name"] = name
|
|
362
|
+
if select_node_id:
|
|
363
|
+
data["selectNodeId"] = select_node_id
|
|
364
|
+
data.update(config)
|
|
365
|
+
return session.workflow_call("flowNode/saveNode", data)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
# ── Testing ──────────────────────────────────────────────────────────────
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def test_code(
|
|
372
|
+
session: Session,
|
|
373
|
+
process_id: str,
|
|
374
|
+
node_id: str,
|
|
375
|
+
code: str,
|
|
376
|
+
input_data: Optional[list] = None,
|
|
377
|
+
action_id: str = "",
|
|
378
|
+
version: str = "",
|
|
379
|
+
) -> dict[str, Any]:
|
|
380
|
+
"""Test a code block node.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
session: Active session
|
|
384
|
+
process_id: Process ID
|
|
385
|
+
node_id: Code node ID
|
|
386
|
+
code: Code to execute
|
|
387
|
+
input_data: Input parameter list [{name, value, type}]
|
|
388
|
+
action_id: Action ID
|
|
389
|
+
version: Code version
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
Test execution result with output
|
|
393
|
+
"""
|
|
394
|
+
data: dict[str, Any] = {
|
|
395
|
+
"processId": process_id,
|
|
396
|
+
"nodeId": node_id,
|
|
397
|
+
"code": code,
|
|
398
|
+
}
|
|
399
|
+
if input_data:
|
|
400
|
+
data["inputDatas"] = input_data
|
|
401
|
+
if action_id:
|
|
402
|
+
data["actionId"] = action_id
|
|
403
|
+
if version:
|
|
404
|
+
data["version"] = version
|
|
405
|
+
return session.workflow_call("flowNode/codeTest", data)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def test_webhook(
|
|
409
|
+
session: Session,
|
|
410
|
+
process_id: str,
|
|
411
|
+
node_id: str,
|
|
412
|
+
url: str,
|
|
413
|
+
method: str = "POST",
|
|
414
|
+
headers: Optional[list] = None,
|
|
415
|
+
body: str = "",
|
|
416
|
+
content_type: str = "application/json",
|
|
417
|
+
params: Optional[list] = None,
|
|
418
|
+
auth_id: str = "",
|
|
419
|
+
settings: Optional[dict] = None,
|
|
420
|
+
) -> dict[str, Any]:
|
|
421
|
+
"""Test a WebHook request.
|
|
422
|
+
|
|
423
|
+
Args:
|
|
424
|
+
session: Active session
|
|
425
|
+
process_id: Process ID
|
|
426
|
+
node_id: WebHook node ID
|
|
427
|
+
url: Target URL
|
|
428
|
+
method: HTTP method
|
|
429
|
+
headers: Request headers [{name, value}]
|
|
430
|
+
body: Request body (JSON string)
|
|
431
|
+
content_type: Content-Type header
|
|
432
|
+
params: URL parameters [{name, value}]
|
|
433
|
+
auth_id: Authentication config ID
|
|
434
|
+
settings: Additional settings
|
|
435
|
+
|
|
436
|
+
Returns:
|
|
437
|
+
WebHook response data
|
|
438
|
+
"""
|
|
439
|
+
data: dict[str, Any] = {
|
|
440
|
+
"processId": process_id,
|
|
441
|
+
"nodeId": node_id,
|
|
442
|
+
"url": url,
|
|
443
|
+
"method": method,
|
|
444
|
+
"contentType": content_type,
|
|
445
|
+
}
|
|
446
|
+
if headers:
|
|
447
|
+
data["headers"] = headers
|
|
448
|
+
if body:
|
|
449
|
+
data["body"] = body
|
|
450
|
+
if params:
|
|
451
|
+
data["params"] = params
|
|
452
|
+
if auth_id:
|
|
453
|
+
data["authId"] = auth_id
|
|
454
|
+
if settings:
|
|
455
|
+
data["settings"] = settings
|
|
456
|
+
return session.workflow_call("flowNode/webHookTestRequest", data)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def test_aigc(
|
|
460
|
+
session: Session,
|
|
461
|
+
process_id: str,
|
|
462
|
+
node_id: str,
|
|
463
|
+
prompt: str,
|
|
464
|
+
model: str = "",
|
|
465
|
+
system_message: str = "",
|
|
466
|
+
temperature: float = 0.7,
|
|
467
|
+
outputs: Optional[list] = None,
|
|
468
|
+
action_id: str = "",
|
|
469
|
+
) -> dict[str, Any]:
|
|
470
|
+
"""Test an AI text generation node.
|
|
471
|
+
|
|
472
|
+
Args:
|
|
473
|
+
session: Active session
|
|
474
|
+
process_id: Process ID
|
|
475
|
+
node_id: AI node ID
|
|
476
|
+
prompt: User prompt
|
|
477
|
+
model: AI model name
|
|
478
|
+
system_message: System message
|
|
479
|
+
temperature: Temperature (0-1)
|
|
480
|
+
outputs: Output field definitions
|
|
481
|
+
action_id: Action ID
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
AI generation result
|
|
485
|
+
"""
|
|
486
|
+
data: dict[str, Any] = {
|
|
487
|
+
"processId": process_id,
|
|
488
|
+
"nodeId": node_id,
|
|
489
|
+
"prompt": prompt,
|
|
490
|
+
"temperature": temperature,
|
|
491
|
+
}
|
|
492
|
+
if model:
|
|
493
|
+
data["model"] = model
|
|
494
|
+
if system_message:
|
|
495
|
+
data["systemMessage"] = system_message
|
|
496
|
+
if outputs:
|
|
497
|
+
data["outputs"] = outputs
|
|
498
|
+
if action_id:
|
|
499
|
+
data["actionId"] = action_id
|
|
500
|
+
return session.workflow_call("flowNode/aigcTest", data)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def test_basic_auth(
|
|
504
|
+
session: Session,
|
|
505
|
+
process_id: str,
|
|
506
|
+
user_name: str,
|
|
507
|
+
password: str,
|
|
508
|
+
) -> dict[str, Any]:
|
|
509
|
+
"""Test basic authentication credentials.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
session: Active session
|
|
513
|
+
process_id: Process ID
|
|
514
|
+
user_name: Username
|
|
515
|
+
password: Password
|
|
516
|
+
|
|
517
|
+
Returns:
|
|
518
|
+
Auth test result
|
|
519
|
+
"""
|
|
520
|
+
return session.workflow_call(
|
|
521
|
+
"flowNode/basicAuthTest",
|
|
522
|
+
{"processId": process_id, "userName": user_name, "password": password},
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
# ── WebHook Data ─────────────────────────────────────────────────────────
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def get_webhook_data(
|
|
530
|
+
session: Session,
|
|
531
|
+
process_id: str,
|
|
532
|
+
node_id: str,
|
|
533
|
+
select_node_id: str = "",
|
|
534
|
+
) -> dict[str, Any]:
|
|
535
|
+
"""Get received WebHook data for a node.
|
|
536
|
+
|
|
537
|
+
Args:
|
|
538
|
+
session: Active session
|
|
539
|
+
process_id: Process ID
|
|
540
|
+
node_id: WebHook node ID
|
|
541
|
+
select_node_id: Context node
|
|
542
|
+
|
|
543
|
+
Returns:
|
|
544
|
+
WebHook received data
|
|
545
|
+
"""
|
|
546
|
+
data: dict[str, Any] = {"processId": process_id, "nodeId": node_id}
|
|
547
|
+
if select_node_id:
|
|
548
|
+
data["selectNodeId"] = select_node_id
|
|
549
|
+
return session.workflow_call("flowNode/getWebHookData", data)
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
# ── Utilities ────────────────────────────────────────────────────────────
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def json_to_controls(
|
|
556
|
+
session: Session,
|
|
557
|
+
json_str: str,
|
|
558
|
+
) -> dict[str, Any]:
|
|
559
|
+
"""Convert JSON string to workflow controls.
|
|
560
|
+
|
|
561
|
+
Args:
|
|
562
|
+
session: Active session
|
|
563
|
+
json_str: JSON string to convert
|
|
564
|
+
|
|
565
|
+
Returns:
|
|
566
|
+
Converted controls list
|
|
567
|
+
"""
|
|
568
|
+
return session.workflow_call(
|
|
569
|
+
"flowNode/jsonToControls",
|
|
570
|
+
{"json": json_str},
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def get_node_form_property(
|
|
575
|
+
session: Session,
|
|
576
|
+
process_id: str,
|
|
577
|
+
node_id: str,
|
|
578
|
+
select_node_id: str = "",
|
|
579
|
+
) -> dict[str, Any]:
|
|
580
|
+
"""Get node form properties.
|
|
581
|
+
|
|
582
|
+
Args:
|
|
583
|
+
session: Active session
|
|
584
|
+
process_id: Process ID
|
|
585
|
+
node_id: Node ID
|
|
586
|
+
select_node_id: Context node
|
|
587
|
+
|
|
588
|
+
Returns:
|
|
589
|
+
Form property config
|
|
590
|
+
"""
|
|
591
|
+
data: dict[str, Any] = {"processId": process_id, "nodeId": node_id}
|
|
592
|
+
if select_node_id:
|
|
593
|
+
data["selectNodeId"] = select_node_id
|
|
594
|
+
return session.workflow_call("flowNode/getNodeFormProperty", data)
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def get_sub_process_list(
|
|
598
|
+
session: Session,
|
|
599
|
+
process_id: str,
|
|
600
|
+
select_node_id: str = "",
|
|
601
|
+
) -> dict[str, Any]:
|
|
602
|
+
"""Get available sub-processes.
|
|
603
|
+
|
|
604
|
+
Args:
|
|
605
|
+
session: Active session
|
|
606
|
+
process_id: Process ID
|
|
607
|
+
select_node_id: Context node
|
|
608
|
+
|
|
609
|
+
Returns:
|
|
610
|
+
Sub-process list
|
|
611
|
+
"""
|
|
612
|
+
data: dict[str, Any] = {"processId": process_id}
|
|
613
|
+
if select_node_id:
|
|
614
|
+
data["selectNodeId"] = select_node_id
|
|
615
|
+
return session.workflow_call("flowNode/getSubProcessList", data)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
# ── Code Templates ───────────────────────────────────────────────────────
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def get_code_template_list(
|
|
622
|
+
session: Session,
|
|
623
|
+
keyword: str = "",
|
|
624
|
+
source: int = 0,
|
|
625
|
+
template_type: int = 0,
|
|
626
|
+
page_index: int = 1,
|
|
627
|
+
page_size: int = 50,
|
|
628
|
+
) -> dict[str, Any]:
|
|
629
|
+
"""Get code template list.
|
|
630
|
+
|
|
631
|
+
Args:
|
|
632
|
+
session: Active session
|
|
633
|
+
keyword: Search keyword
|
|
634
|
+
source: Template source
|
|
635
|
+
template_type: Template type
|
|
636
|
+
page_index: Page number
|
|
637
|
+
page_size: Items per page
|
|
638
|
+
|
|
639
|
+
Returns:
|
|
640
|
+
Template list
|
|
641
|
+
"""
|
|
642
|
+
data: dict[str, Any] = {"pageIndex": page_index, "pageSize": page_size}
|
|
643
|
+
if keyword:
|
|
644
|
+
data["keyword"] = keyword
|
|
645
|
+
if source:
|
|
646
|
+
data["source"] = source
|
|
647
|
+
if template_type:
|
|
648
|
+
data["type"] = template_type
|
|
649
|
+
return session.workflow_call("flowNode/getCodeTemplateList", data)
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
def create_code_template(
|
|
653
|
+
session: Session,
|
|
654
|
+
name: str,
|
|
655
|
+
code: str,
|
|
656
|
+
template_type: int = 0,
|
|
657
|
+
source: int = 0,
|
|
658
|
+
input_data: Optional[list] = None,
|
|
659
|
+
) -> dict[str, Any]:
|
|
660
|
+
"""Create a code template.
|
|
661
|
+
|
|
662
|
+
Args:
|
|
663
|
+
session: Active session
|
|
664
|
+
name: Template name
|
|
665
|
+
code: Template code
|
|
666
|
+
template_type: Template type
|
|
667
|
+
source: Template source
|
|
668
|
+
input_data: Input parameters
|
|
669
|
+
|
|
670
|
+
Returns:
|
|
671
|
+
Created template info
|
|
672
|
+
"""
|
|
673
|
+
data: dict[str, Any] = {"name": name, "code": code, "type": template_type, "source": source}
|
|
674
|
+
if input_data:
|
|
675
|
+
data["inputDatas"] = input_data
|
|
676
|
+
return session.workflow_call("flowNode/createCodeTemplate", data)
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
def update_code_template(
|
|
680
|
+
session: Session,
|
|
681
|
+
template_id: str,
|
|
682
|
+
name: str = "",
|
|
683
|
+
code: str = "",
|
|
684
|
+
deleted: bool = False,
|
|
685
|
+
input_data: Optional[list] = None,
|
|
686
|
+
) -> dict[str, Any]:
|
|
687
|
+
"""Update or delete a code template.
|
|
688
|
+
|
|
689
|
+
Args:
|
|
690
|
+
session: Active session
|
|
691
|
+
template_id: Template ID
|
|
692
|
+
name: New name
|
|
693
|
+
code: New code
|
|
694
|
+
deleted: Set True to delete
|
|
695
|
+
input_data: Updated input parameters
|
|
696
|
+
|
|
697
|
+
Returns:
|
|
698
|
+
Update result
|
|
699
|
+
"""
|
|
700
|
+
data: dict[str, Any] = {"id": template_id}
|
|
701
|
+
if name:
|
|
702
|
+
data["name"] = name
|
|
703
|
+
if code:
|
|
704
|
+
data["code"] = code
|
|
705
|
+
if deleted:
|
|
706
|
+
data["deleted"] = True
|
|
707
|
+
if input_data:
|
|
708
|
+
data["inputDatas"] = input_data
|
|
709
|
+
return session.workflow_call("flowNode/updateCodeTemplate", data)
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
# ── App/Control Helpers ──────────────────────────────────────────────────
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def get_flow_app_dtos(
|
|
716
|
+
session: Session,
|
|
717
|
+
process_id: str,
|
|
718
|
+
node_id: str,
|
|
719
|
+
select_node_id: str = "",
|
|
720
|
+
source_app_id: str = "",
|
|
721
|
+
data_source: int = 0,
|
|
722
|
+
enum_default: int = 0,
|
|
723
|
+
field_type: int = 0,
|
|
724
|
+
) -> dict[str, Any]:
|
|
725
|
+
"""Get available app/field data for a node configuration.
|
|
726
|
+
|
|
727
|
+
Args:
|
|
728
|
+
session: Active session
|
|
729
|
+
process_id: Process ID
|
|
730
|
+
node_id: Node ID
|
|
731
|
+
select_node_id: Context node
|
|
732
|
+
source_app_id: Source app ID
|
|
733
|
+
data_source: Data source type
|
|
734
|
+
enum_default: Default enum
|
|
735
|
+
field_type: Field type filter
|
|
736
|
+
|
|
737
|
+
Returns:
|
|
738
|
+
Available app/field data
|
|
739
|
+
"""
|
|
740
|
+
data: dict[str, Any] = {"processId": process_id, "nodeId": node_id}
|
|
741
|
+
if select_node_id:
|
|
742
|
+
data["selectNodeId"] = select_node_id
|
|
743
|
+
if source_app_id:
|
|
744
|
+
data["sourceAppId"] = source_app_id
|
|
745
|
+
if data_source:
|
|
746
|
+
data["dataSource"] = data_source
|
|
747
|
+
if enum_default:
|
|
748
|
+
data["enumDefault"] = enum_default
|
|
749
|
+
if field_type:
|
|
750
|
+
data["type"] = field_type
|
|
751
|
+
return session.workflow_call("flowNode/getFlowAppDtos", data)
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
def get_start_event_deploy(
|
|
755
|
+
session: Session,
|
|
756
|
+
process_id: str,
|
|
757
|
+
node_id: str,
|
|
758
|
+
app_id: str = "",
|
|
759
|
+
app_type: int = 0,
|
|
760
|
+
control_id: str = "",
|
|
761
|
+
select_node_id: str = "",
|
|
762
|
+
) -> dict[str, Any]:
|
|
763
|
+
"""Get start event deployment config.
|
|
764
|
+
|
|
765
|
+
Args:
|
|
766
|
+
session: Active session
|
|
767
|
+
process_id: Process ID
|
|
768
|
+
node_id: Start node ID
|
|
769
|
+
app_id: App ID
|
|
770
|
+
app_type: App type
|
|
771
|
+
control_id: Control ID
|
|
772
|
+
select_node_id: Context node
|
|
773
|
+
|
|
774
|
+
Returns:
|
|
775
|
+
Start event configuration
|
|
776
|
+
"""
|
|
777
|
+
data: dict[str, Any] = {"processId": process_id, "nodeId": node_id}
|
|
778
|
+
if app_id:
|
|
779
|
+
data["appId"] = app_id
|
|
780
|
+
if app_type:
|
|
781
|
+
data["appType"] = app_type
|
|
782
|
+
if control_id:
|
|
783
|
+
data["controlId"] = control_id
|
|
784
|
+
if select_node_id:
|
|
785
|
+
data["selectNodeId"] = select_node_id
|
|
786
|
+
return session.workflow_call("flowNode/getStartEventDeploy", data)
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
# ── Data Processing Convenience Functions ────────────────────────────────
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
def save_action_node(
|
|
793
|
+
session: Session,
|
|
794
|
+
process_id: str,
|
|
795
|
+
node_id: str,
|
|
796
|
+
action_id: str,
|
|
797
|
+
app_id: str,
|
|
798
|
+
fields: Optional[list] = None,
|
|
799
|
+
name: str = "",
|
|
800
|
+
app_type: int = 1,
|
|
801
|
+
select_node_id: str = "",
|
|
802
|
+
filters: Optional[list] = None,
|
|
803
|
+
operate_condition: Optional[list] = None,
|
|
804
|
+
sorts: Optional[list] = None,
|
|
805
|
+
execute_type: int = 0,
|
|
806
|
+
) -> dict[str, Any]:
|
|
807
|
+
"""Save configuration for a data ACTION node (type 6).
|
|
808
|
+
|
|
809
|
+
Used for: add record, edit record, delete record, create relation, etc.
|
|
810
|
+
|
|
811
|
+
Args:
|
|
812
|
+
session: Active session
|
|
813
|
+
process_id: Process ID
|
|
814
|
+
node_id: Node ID
|
|
815
|
+
action_id: Operation type:
|
|
816
|
+
'1'=ADD, '2'=EDIT, '3'=DELETE, '5'=CREATE_RECORD,
|
|
817
|
+
'6'=REFRESH_SINGLE, '20'=RELATION
|
|
818
|
+
app_id: Target worksheet ID
|
|
819
|
+
fields: Field mapping [{fieldId, type, fieldValue, fieldValueId, nodeId}]
|
|
820
|
+
name: Node name
|
|
821
|
+
app_type: App type (1=SHEET default)
|
|
822
|
+
select_node_id: Source data node ID
|
|
823
|
+
filters: Filter conditions
|
|
824
|
+
operate_condition: Operation conditions
|
|
825
|
+
sorts: Sort rules
|
|
826
|
+
execute_type: Execution behavior (0=default)
|
|
827
|
+
|
|
828
|
+
Returns:
|
|
829
|
+
Save result
|
|
830
|
+
"""
|
|
831
|
+
config: dict[str, Any] = {
|
|
832
|
+
"actionId": action_id,
|
|
833
|
+
"appId": app_id,
|
|
834
|
+
"appType": app_type,
|
|
835
|
+
}
|
|
836
|
+
if fields:
|
|
837
|
+
config["fields"] = fields
|
|
838
|
+
if select_node_id:
|
|
839
|
+
config["selectNodeId"] = select_node_id
|
|
840
|
+
if filters:
|
|
841
|
+
config["filters"] = filters
|
|
842
|
+
if operate_condition:
|
|
843
|
+
config["operateCondition"] = operate_condition
|
|
844
|
+
if sorts:
|
|
845
|
+
config["sorts"] = sorts
|
|
846
|
+
if execute_type:
|
|
847
|
+
config["executeType"] = execute_type
|
|
848
|
+
return save_node(session, process_id, node_id, NODE_TYPE["ACTION"], config, name=name)
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
def save_search_node(
|
|
852
|
+
session: Session,
|
|
853
|
+
process_id: str,
|
|
854
|
+
node_id: str,
|
|
855
|
+
action_id: str,
|
|
856
|
+
app_id: str = "",
|
|
857
|
+
fields: Optional[list] = None,
|
|
858
|
+
name: str = "",
|
|
859
|
+
select_node_id: str = "",
|
|
860
|
+
operate_condition: Optional[list] = None,
|
|
861
|
+
sorts: Optional[list] = None,
|
|
862
|
+
random: bool = False,
|
|
863
|
+
execute_type: int = 0,
|
|
864
|
+
filters: Optional[list] = None,
|
|
865
|
+
) -> dict[str, Any]:
|
|
866
|
+
"""Save configuration for a SEARCH node (type 7) - get single record.
|
|
867
|
+
|
|
868
|
+
Args:
|
|
869
|
+
session: Active session
|
|
870
|
+
process_id: Process ID
|
|
871
|
+
node_id: Node ID
|
|
872
|
+
action_id: Search type:
|
|
873
|
+
'406'=WORKSHEET_FIND, '407'=BATCH_FIND,
|
|
874
|
+
'420'=RECORD_LINK_FIND, '421'=RECORD_UPDATE, '422'=RECORD_DELETE
|
|
875
|
+
app_id: Target worksheet ID (for WORKSHEET_FIND)
|
|
876
|
+
fields: Return field list
|
|
877
|
+
name: Node name
|
|
878
|
+
select_node_id: Source data node ID
|
|
879
|
+
operate_condition: Query conditions
|
|
880
|
+
sorts: Sort rules
|
|
881
|
+
random: Pick random record
|
|
882
|
+
execute_type: When not found: 0=abort, 1=create, 2=continue
|
|
883
|
+
filters: Filter groups
|
|
884
|
+
|
|
885
|
+
Returns:
|
|
886
|
+
Save result
|
|
887
|
+
"""
|
|
888
|
+
config: dict[str, Any] = {"actionId": action_id}
|
|
889
|
+
if app_id:
|
|
890
|
+
config["appId"] = app_id
|
|
891
|
+
if fields:
|
|
892
|
+
config["fields"] = fields
|
|
893
|
+
if select_node_id:
|
|
894
|
+
config["selectNodeId"] = select_node_id
|
|
895
|
+
if operate_condition:
|
|
896
|
+
config["operateCondition"] = operate_condition
|
|
897
|
+
if sorts:
|
|
898
|
+
config["sorts"] = sorts
|
|
899
|
+
if random:
|
|
900
|
+
config["random"] = random
|
|
901
|
+
if execute_type:
|
|
902
|
+
config["executeType"] = execute_type
|
|
903
|
+
if filters:
|
|
904
|
+
config["filters"] = filters
|
|
905
|
+
return save_node(session, process_id, node_id, NODE_TYPE["SEARCH"], config, name=name)
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
def save_get_more_record_node(
|
|
909
|
+
session: Session,
|
|
910
|
+
process_id: str,
|
|
911
|
+
node_id: str,
|
|
912
|
+
action_id: str,
|
|
913
|
+
app_id: str = "",
|
|
914
|
+
fields: Optional[list] = None,
|
|
915
|
+
name: str = "",
|
|
916
|
+
select_node_id: str = "",
|
|
917
|
+
operate_condition: Optional[list] = None,
|
|
918
|
+
sorts: Optional[list] = None,
|
|
919
|
+
number_field_value: Optional[dict] = None,
|
|
920
|
+
filters: Optional[list] = None,
|
|
921
|
+
random: bool = False,
|
|
922
|
+
) -> dict[str, Any]:
|
|
923
|
+
"""Save configuration for a GET_MORE_RECORD node (type 13).
|
|
924
|
+
|
|
925
|
+
Args:
|
|
926
|
+
session: Active session
|
|
927
|
+
process_id: Process ID
|
|
928
|
+
node_id: Node ID
|
|
929
|
+
action_id: Operation type:
|
|
930
|
+
'400'=FROM_WORKSHEET, '401'=FROM_RECORD, '402'=FROM_ADD,
|
|
931
|
+
'403'=FROM_ARRAY, '404'=FROM_CODE_ARRAY,
|
|
932
|
+
'412'=BATCH_UPDATE, '413'=BATCH_DELETE, '415'=REFRESH_MULTIPLE
|
|
933
|
+
app_id: Target worksheet ID (for FROM_WORKSHEET, BATCH_UPDATE, BATCH_DELETE)
|
|
934
|
+
fields: Field mapping
|
|
935
|
+
name: Node name
|
|
936
|
+
select_node_id: Source node ID (for FROM_RECORD etc.)
|
|
937
|
+
operate_condition: Filter/query conditions
|
|
938
|
+
sorts: Sort rules
|
|
939
|
+
number_field_value: Record count limit config
|
|
940
|
+
filters: Filter groups
|
|
941
|
+
random: Pick random
|
|
942
|
+
|
|
943
|
+
Returns:
|
|
944
|
+
Save result
|
|
945
|
+
"""
|
|
946
|
+
config: dict[str, Any] = {"actionId": action_id}
|
|
947
|
+
if app_id:
|
|
948
|
+
config["appId"] = app_id
|
|
949
|
+
if fields:
|
|
950
|
+
config["fields"] = fields
|
|
951
|
+
if select_node_id:
|
|
952
|
+
config["selectNodeId"] = select_node_id
|
|
953
|
+
if operate_condition:
|
|
954
|
+
config["operateCondition"] = operate_condition
|
|
955
|
+
if sorts:
|
|
956
|
+
config["sorts"] = sorts
|
|
957
|
+
if number_field_value:
|
|
958
|
+
config["numberFieldValue"] = number_field_value
|
|
959
|
+
if filters:
|
|
960
|
+
config["filters"] = filters
|
|
961
|
+
if random:
|
|
962
|
+
config["random"] = random
|
|
963
|
+
return save_node(session, process_id, node_id, NODE_TYPE["GET_MORE_RECORD"], config, name=name)
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
def get_app_template_controls(
|
|
967
|
+
session: Session,
|
|
968
|
+
process_id: str,
|
|
969
|
+
node_id: str,
|
|
970
|
+
app_id: str,
|
|
971
|
+
app_type: int = 1,
|
|
972
|
+
select_node_id: str = "",
|
|
973
|
+
action_id: str = "",
|
|
974
|
+
) -> dict[str, Any]:
|
|
975
|
+
"""Get available worksheet controls/fields for node configuration.
|
|
976
|
+
|
|
977
|
+
Useful for discovering field IDs before configuring ACTION/SEARCH nodes.
|
|
978
|
+
|
|
979
|
+
Args:
|
|
980
|
+
session: Active session
|
|
981
|
+
process_id: Process ID
|
|
982
|
+
node_id: Node ID
|
|
983
|
+
app_id: Worksheet ID
|
|
984
|
+
app_type: App type (1=SHEET)
|
|
985
|
+
select_node_id: Context node
|
|
986
|
+
action_id: Action context
|
|
987
|
+
|
|
988
|
+
Returns:
|
|
989
|
+
Controls/fields list for the worksheet
|
|
990
|
+
"""
|
|
991
|
+
data: dict[str, Any] = {
|
|
992
|
+
"processId": process_id,
|
|
993
|
+
"nodeId": node_id,
|
|
994
|
+
"appId": app_id,
|
|
995
|
+
"appType": app_type,
|
|
996
|
+
}
|
|
997
|
+
if select_node_id:
|
|
998
|
+
data["selectNodeId"] = select_node_id
|
|
999
|
+
if action_id:
|
|
1000
|
+
data["actionId"] = action_id
|
|
1001
|
+
return session.workflow_call("flowNode/getAppTemplateControls", data)
|