@nocobase/plugin-flow-engine 2.0.0-alpha.7 → 2.0.0-alpha.71
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.
- package/dist/externalVersion.js +9 -9
- package/dist/locale/de-DE.json +62 -0
- package/dist/locale/en-US.json +57 -45
- package/dist/locale/es-ES.json +62 -0
- package/dist/locale/fr-FR.json +62 -0
- package/dist/locale/hu-HU.json +62 -0
- package/dist/locale/id-ID.json +62 -0
- package/dist/locale/index.d.ts +114 -90
- package/dist/locale/it-IT.json +62 -0
- package/dist/locale/ja-JP.json +62 -0
- package/dist/locale/ko-KR.json +62 -0
- package/dist/locale/nl-NL.json +62 -0
- package/dist/locale/pt-BR.json +62 -0
- package/dist/locale/ru-RU.json +62 -0
- package/dist/locale/tr-TR.json +62 -0
- package/dist/locale/uk-UA.json +62 -0
- package/dist/locale/vi-VN.json +62 -0
- package/dist/locale/zh-CN.json +58 -46
- package/dist/locale/zh-TW.json +62 -0
- package/dist/node_modules/ses/package.json +1 -1
- package/dist/server/collections/flowsql.js +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +6 -0
- package/dist/server/plugin.d.ts +0 -5
- package/dist/server/plugin.js +17 -98
- package/dist/server/repository.d.ts +13 -2
- package/dist/server/repository.js +258 -8
- package/dist/server/server.js +22 -3
- package/dist/server/template/resolver.js +10 -6
- package/dist/server/variables/records.d.ts +38 -0
- package/dist/server/variables/records.js +120 -0
- package/dist/server/variables/registry.d.ts +10 -0
- package/dist/server/variables/registry.js +278 -64
- package/dist/server/variables/selects.d.ts +19 -0
- package/dist/server/variables/selects.js +80 -0
- package/dist/server/variables/utils.d.ts +17 -0
- package/dist/server/variables/utils.js +163 -0
- package/package.json +2 -2
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Cache } from '@nocobase/cache';
|
|
10
10
|
import { Repository, Transaction, Transactionable } from '@nocobase/database';
|
|
11
|
-
import { ChildOptions, SchemaNode } from './dao/ui_schema_node_dao';
|
|
11
|
+
import { ChildOptions, SchemaNode, TargetPosition } from './dao/ui_schema_node_dao';
|
|
12
12
|
export interface GetJsonSchemaOptions {
|
|
13
13
|
includeAsyncNode?: boolean;
|
|
14
14
|
readFromCache?: boolean;
|
|
@@ -18,6 +18,13 @@ export interface GetPropertiesOptions {
|
|
|
18
18
|
readFromCache?: boolean;
|
|
19
19
|
transaction?: Transaction;
|
|
20
20
|
}
|
|
21
|
+
export type FlowModelAttachPosition = 'first' | 'last' | TargetPosition;
|
|
22
|
+
export interface FlowModelAttachOptions {
|
|
23
|
+
parentId: string;
|
|
24
|
+
subKey: string;
|
|
25
|
+
subType: 'array' | 'object';
|
|
26
|
+
position?: FlowModelAttachPosition;
|
|
27
|
+
}
|
|
21
28
|
type BreakRemoveOnType = {
|
|
22
29
|
[key: string]: any;
|
|
23
30
|
};
|
|
@@ -51,6 +58,7 @@ export declare class FlowModelRepository extends Repository {
|
|
|
51
58
|
getParentJsonSchema(uid: string, options?: GetJsonSchemaOptions): Promise<any>;
|
|
52
59
|
getParentProperty(uid: string, options?: GetPropertiesOptions): Promise<any>;
|
|
53
60
|
getJsonSchema(uid: string, options?: GetJsonSchemaOptions): Promise<any>;
|
|
61
|
+
static optionsToJson(options: any): any;
|
|
54
62
|
nodesToSchema(nodes: any, rootUid: any): {
|
|
55
63
|
uid: any;
|
|
56
64
|
"x-async": boolean;
|
|
@@ -70,7 +78,9 @@ export declare class FlowModelRepository extends Repository {
|
|
|
70
78
|
}): Promise<void>;
|
|
71
79
|
remove(uid: string, options?: Transactionable & removeParentOptions): Promise<void>;
|
|
72
80
|
insertAdjacent(position: 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd', target: string, schema: any, options?: InsertAdjacentOptions): Promise<any>;
|
|
73
|
-
duplicate(
|
|
81
|
+
duplicate(modelUid: string, options?: Transactionable): Promise<any>;
|
|
82
|
+
private dedupeNodesForDuplicate;
|
|
83
|
+
private replaceStepParamsModelUids;
|
|
74
84
|
insert(schema: any, options?: Transactionable): Promise<any>;
|
|
75
85
|
insertNewSchema(schema: any, options?: Transactionable & {
|
|
76
86
|
returnNode?: boolean;
|
|
@@ -111,6 +121,7 @@ export declare class FlowModelRepository extends Repository {
|
|
|
111
121
|
findModelByParentId(parentUid: string, options?: GetJsonSchemaOptions & {
|
|
112
122
|
subKey?: string;
|
|
113
123
|
}): Promise<any>;
|
|
124
|
+
attach(uid: string, attachOptions: FlowModelAttachOptions, options?: Transactionable): Promise<any>;
|
|
114
125
|
move(options: any): Promise<any>;
|
|
115
126
|
}
|
|
116
127
|
export default FlowModelRepository;
|
|
@@ -204,6 +204,9 @@ const _FlowModelRepository = class _FlowModelRepository extends import_database.
|
|
|
204
204
|
}
|
|
205
205
|
return this.doGetJsonSchema(uid2, options);
|
|
206
206
|
}
|
|
207
|
+
static optionsToJson(options) {
|
|
208
|
+
return import_lodash.default.isPlainObject(options) ? options : JSON.parse(options);
|
|
209
|
+
}
|
|
207
210
|
nodesToSchema(nodes, rootUid) {
|
|
208
211
|
const nodeAttributeSanitize = (node) => {
|
|
209
212
|
const schema = {
|
|
@@ -426,13 +429,122 @@ const _FlowModelRepository = class _FlowModelRepository extends import_database.
|
|
|
426
429
|
await this.clearXUidPathCache(result["uid"], transaction2);
|
|
427
430
|
return result;
|
|
428
431
|
}
|
|
429
|
-
async duplicate(
|
|
430
|
-
|
|
431
|
-
if (!(
|
|
432
|
+
async duplicate(modelUid, options) {
|
|
433
|
+
let nodes = await this.findNodesById(modelUid, { ...options, includeAsyncNode: true });
|
|
434
|
+
if (!(nodes == null ? void 0 : nodes.length)) {
|
|
432
435
|
return null;
|
|
433
436
|
}
|
|
434
|
-
this.
|
|
435
|
-
|
|
437
|
+
nodes = this.dedupeNodesForDuplicate(nodes, modelUid);
|
|
438
|
+
const uidMap = {};
|
|
439
|
+
for (const n of nodes) {
|
|
440
|
+
uidMap[n["uid"]] = (0, import_utils.uid)();
|
|
441
|
+
}
|
|
442
|
+
const sorted = [...nodes].sort((a, b) => {
|
|
443
|
+
if (a.depth !== b.depth) return a.depth - b.depth;
|
|
444
|
+
const ap = a.parent || "";
|
|
445
|
+
const bp = b.parent || "";
|
|
446
|
+
if (ap !== bp) return ap < bp ? -1 : 1;
|
|
447
|
+
const at = a.type || "";
|
|
448
|
+
const bt = b.type || "";
|
|
449
|
+
if (at !== bt) return at < bt ? -1 : 1;
|
|
450
|
+
const as = a.sort ?? 0;
|
|
451
|
+
const bs = b.sort ?? 0;
|
|
452
|
+
return as - bs;
|
|
453
|
+
});
|
|
454
|
+
for (const n of sorted) {
|
|
455
|
+
const oldUid = n["uid"];
|
|
456
|
+
const newUid = uidMap[oldUid];
|
|
457
|
+
const oldParentUid = n["parent"];
|
|
458
|
+
const newParentUid = uidMap[oldParentUid] ?? null;
|
|
459
|
+
const optionsObj = this.replaceStepParamsModelUids(
|
|
460
|
+
import_lodash.default.isPlainObject(n.options) ? n.options : JSON.parse(n.options),
|
|
461
|
+
uidMap
|
|
462
|
+
);
|
|
463
|
+
if (newParentUid) {
|
|
464
|
+
optionsObj.parent = newParentUid;
|
|
465
|
+
optionsObj.parentId = newParentUid;
|
|
466
|
+
}
|
|
467
|
+
const schemaNode = {
|
|
468
|
+
uid: newUid,
|
|
469
|
+
["x-async"]: !!n.async,
|
|
470
|
+
...optionsObj
|
|
471
|
+
};
|
|
472
|
+
if (newParentUid) {
|
|
473
|
+
schemaNode.childOptions = {
|
|
474
|
+
parentUid: newParentUid,
|
|
475
|
+
type: n.type,
|
|
476
|
+
position: "last"
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
await this.insertSingleNode(schemaNode, { transaction: options == null ? void 0 : options.transaction });
|
|
480
|
+
}
|
|
481
|
+
return this.findModelById(uidMap[modelUid], { ...options });
|
|
482
|
+
}
|
|
483
|
+
dedupeNodesForDuplicate(nodes, rootUid) {
|
|
484
|
+
if (!Array.isArray(nodes) || nodes.length <= 1) {
|
|
485
|
+
return nodes;
|
|
486
|
+
}
|
|
487
|
+
const rowsByUid = import_lodash.default.groupBy(nodes, "uid");
|
|
488
|
+
const uniqueUids = Object.keys(rowsByUid);
|
|
489
|
+
if (uniqueUids.length === nodes.length) {
|
|
490
|
+
return nodes;
|
|
491
|
+
}
|
|
492
|
+
const uidsInSubtree = new Set(uniqueUids);
|
|
493
|
+
const rootDepthByUid = /* @__PURE__ */ new Map();
|
|
494
|
+
for (const uid2 of uniqueUids) {
|
|
495
|
+
const rows = rowsByUid[uid2] || [];
|
|
496
|
+
const depths = rows.map((row) => Number((row == null ? void 0 : row.depth) ?? 0));
|
|
497
|
+
rootDepthByUid.set(uid2, depths.length ? Math.min(...depths) : 0);
|
|
498
|
+
}
|
|
499
|
+
const pickRowForUid = (uid2, rows) => {
|
|
500
|
+
if (!(rows == null ? void 0 : rows.length)) return null;
|
|
501
|
+
if (rows.length === 1) return rows[0];
|
|
502
|
+
if (uid2 === rootUid) return rows[0];
|
|
503
|
+
let bestRow = rows[0];
|
|
504
|
+
let bestParentRootDepth = -1;
|
|
505
|
+
for (const row of rows) {
|
|
506
|
+
const parentUid = row == null ? void 0 : row.parent;
|
|
507
|
+
if (!parentUid || !uidsInSubtree.has(parentUid)) {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
const parentRootDepth = rootDepthByUid.get(parentUid) ?? -1;
|
|
511
|
+
if (parentRootDepth > bestParentRootDepth) {
|
|
512
|
+
bestParentRootDepth = parentRootDepth;
|
|
513
|
+
bestRow = row;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return bestRow;
|
|
517
|
+
};
|
|
518
|
+
const uidsInQueryOrder = [];
|
|
519
|
+
const seenUidsInQueryOrder = /* @__PURE__ */ new Set();
|
|
520
|
+
for (const row of nodes) {
|
|
521
|
+
const uid2 = row == null ? void 0 : row.uid;
|
|
522
|
+
if (!uid2 || seenUidsInQueryOrder.has(uid2)) continue;
|
|
523
|
+
seenUidsInQueryOrder.add(uid2);
|
|
524
|
+
uidsInQueryOrder.push(uid2);
|
|
525
|
+
}
|
|
526
|
+
return uidsInQueryOrder.map((uid2) => pickRowForUid(uid2, rowsByUid[uid2])).filter(Boolean);
|
|
527
|
+
}
|
|
528
|
+
replaceStepParamsModelUids(options, uidMap) {
|
|
529
|
+
const opts = options && typeof options === "object" ? options : {};
|
|
530
|
+
const replaceUidString = (v) => typeof v === "string" && uidMap[v] ? uidMap[v] : v;
|
|
531
|
+
const replaceInPlace = (val) => {
|
|
532
|
+
if (Array.isArray(val)) {
|
|
533
|
+
for (let i = 0; i < val.length; i++) {
|
|
534
|
+
val[i] = replaceInPlace(val[i]);
|
|
535
|
+
}
|
|
536
|
+
return val;
|
|
537
|
+
}
|
|
538
|
+
if (val && typeof val === "object") {
|
|
539
|
+
for (const k of Object.keys(val)) {
|
|
540
|
+
val[k] = replaceInPlace(val[k]);
|
|
541
|
+
}
|
|
542
|
+
return val;
|
|
543
|
+
}
|
|
544
|
+
return replaceUidString(val);
|
|
545
|
+
};
|
|
546
|
+
if (opts.stepParams) opts.stepParams = replaceInPlace(opts.stepParams);
|
|
547
|
+
return opts;
|
|
436
548
|
}
|
|
437
549
|
async insert(schema, options) {
|
|
438
550
|
const nodes = _FlowModelRepository.schemaToSingleNodes(schema);
|
|
@@ -1025,11 +1137,11 @@ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and TreeTable.sort
|
|
|
1025
1137
|
const children = nodes.filter((n) => n.parent === rootUid);
|
|
1026
1138
|
const subModels = {};
|
|
1027
1139
|
for (const child of children) {
|
|
1028
|
-
const { subKey, subType } = child.options;
|
|
1140
|
+
const { subKey, subType } = this.optionsToJson(child.options);
|
|
1029
1141
|
if (!subKey) continue;
|
|
1030
1142
|
const model = _FlowModelRepository.nodesToModel(nodes, child["uid"]) || {
|
|
1031
1143
|
uid: child["uid"],
|
|
1032
|
-
...child.options,
|
|
1144
|
+
...this.optionsToJson(child.options),
|
|
1033
1145
|
sortIndex: child.sort
|
|
1034
1146
|
};
|
|
1035
1147
|
model.sortIndex = child.sort;
|
|
@@ -1055,7 +1167,7 @@ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and TreeTable.sort
|
|
|
1055
1167
|
}
|
|
1056
1168
|
return {
|
|
1057
1169
|
uid: rootNode["uid"],
|
|
1058
|
-
...rootNode.options,
|
|
1170
|
+
...this.optionsToJson(rootNode.options),
|
|
1059
1171
|
...Object.keys(filteredSubModels).length > 0 ? { subModels: filteredSubModels } : {}
|
|
1060
1172
|
};
|
|
1061
1173
|
}
|
|
@@ -1136,6 +1248,141 @@ WHERE TreeTable.depth = 1 AND TreeTable.ancestor = :ancestor and TreeTable.sort
|
|
|
1136
1248
|
}
|
|
1137
1249
|
return null;
|
|
1138
1250
|
}
|
|
1251
|
+
async attach(uid2, attachOptions, options) {
|
|
1252
|
+
const { transaction: transaction2 } = options || {};
|
|
1253
|
+
const modelUid = String(uid2 || "").trim();
|
|
1254
|
+
const parentId = String((attachOptions == null ? void 0 : attachOptions.parentId) || "").trim();
|
|
1255
|
+
const subKey = String((attachOptions == null ? void 0 : attachOptions.subKey) || "").trim();
|
|
1256
|
+
const subType = attachOptions == null ? void 0 : attachOptions.subType;
|
|
1257
|
+
if (!modelUid || !parentId || !subKey || subType !== "array" && subType !== "object") {
|
|
1258
|
+
throw new Error("flowModels:attach missing required params");
|
|
1259
|
+
}
|
|
1260
|
+
if (modelUid === parentId) {
|
|
1261
|
+
throw new Error("flowModels:attach cannot attach model to itself");
|
|
1262
|
+
}
|
|
1263
|
+
const treeTable = this.flowModelTreePathTableName;
|
|
1264
|
+
const modelInstance = await this.model.findByPk(modelUid, { transaction: transaction2 });
|
|
1265
|
+
if (!modelInstance) {
|
|
1266
|
+
throw new Error(`flowModels:attach uid '${modelUid}' not found`);
|
|
1267
|
+
}
|
|
1268
|
+
const parentInstance = await this.model.findByPk(parentId, { transaction: transaction2 });
|
|
1269
|
+
if (!parentInstance) {
|
|
1270
|
+
throw new Error(`flowModels:attach parentId '${parentId}' not found`);
|
|
1271
|
+
}
|
|
1272
|
+
const cycle = await this.database.sequelize.query(
|
|
1273
|
+
`SELECT 1 as v
|
|
1274
|
+
FROM ${treeTable}
|
|
1275
|
+
WHERE ancestor = :ancestor AND descendant = :descendant AND depth > 0
|
|
1276
|
+
LIMIT 1`,
|
|
1277
|
+
{
|
|
1278
|
+
type: "SELECT",
|
|
1279
|
+
replacements: {
|
|
1280
|
+
ancestor: modelUid,
|
|
1281
|
+
descendant: parentId
|
|
1282
|
+
},
|
|
1283
|
+
transaction: transaction2
|
|
1284
|
+
}
|
|
1285
|
+
);
|
|
1286
|
+
if (cycle == null ? void 0 : cycle.length) {
|
|
1287
|
+
throw new Error("flowModels:attach cycle detected");
|
|
1288
|
+
}
|
|
1289
|
+
if (subType === "object") {
|
|
1290
|
+
const conflict = await this.database.sequelize.query(
|
|
1291
|
+
`SELECT TreeTable.descendant as uid
|
|
1292
|
+
FROM ${treeTable} as TreeTable
|
|
1293
|
+
LEFT JOIN ${treeTable} as NodeInfo
|
|
1294
|
+
ON NodeInfo.descendant = TreeTable.descendant
|
|
1295
|
+
AND NodeInfo.depth = 0
|
|
1296
|
+
WHERE TreeTable.depth = 1
|
|
1297
|
+
AND TreeTable.ancestor = :ancestor
|
|
1298
|
+
AND NodeInfo.type = :type
|
|
1299
|
+
AND TreeTable.descendant != :uid
|
|
1300
|
+
LIMIT 1`,
|
|
1301
|
+
{
|
|
1302
|
+
type: "SELECT",
|
|
1303
|
+
replacements: {
|
|
1304
|
+
ancestor: parentId,
|
|
1305
|
+
type: subKey,
|
|
1306
|
+
uid: modelUid
|
|
1307
|
+
},
|
|
1308
|
+
transaction: transaction2
|
|
1309
|
+
}
|
|
1310
|
+
);
|
|
1311
|
+
if (conflict == null ? void 0 : conflict.length) {
|
|
1312
|
+
throw new Error(`flowModels:attach subKey '${subKey}' already exists on parent '${parentId}'`);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
const normalizePosition = (input) => {
|
|
1316
|
+
if (!input) return "last";
|
|
1317
|
+
if (input === "first" || input === "last") return input;
|
|
1318
|
+
if (typeof input === "object") {
|
|
1319
|
+
const p = input;
|
|
1320
|
+
const type = p == null ? void 0 : p.type;
|
|
1321
|
+
const target = String((p == null ? void 0 : p.target) || "").trim();
|
|
1322
|
+
if ((type === "before" || type === "after") && target) {
|
|
1323
|
+
return { type, target };
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
throw new Error("flowModels:attach invalid position");
|
|
1327
|
+
};
|
|
1328
|
+
const position = subType === "object" ? "last" : normalizePosition(attachOptions == null ? void 0 : attachOptions.position);
|
|
1329
|
+
if (typeof position === "object") {
|
|
1330
|
+
const target = String(position.target || "").trim();
|
|
1331
|
+
if (target === modelUid) {
|
|
1332
|
+
throw new Error("flowModels:attach position target cannot be itself");
|
|
1333
|
+
}
|
|
1334
|
+
const ok = await this.database.sequelize.query(
|
|
1335
|
+
`SELECT 1 as v
|
|
1336
|
+
FROM ${treeTable} as TreeTable
|
|
1337
|
+
LEFT JOIN ${treeTable} as NodeInfo
|
|
1338
|
+
ON NodeInfo.descendant = TreeTable.descendant
|
|
1339
|
+
AND NodeInfo.depth = 0
|
|
1340
|
+
WHERE TreeTable.depth = 1
|
|
1341
|
+
AND TreeTable.ancestor = :ancestor
|
|
1342
|
+
AND TreeTable.descendant = :descendant
|
|
1343
|
+
AND NodeInfo.type = :type
|
|
1344
|
+
LIMIT 1`,
|
|
1345
|
+
{
|
|
1346
|
+
type: "SELECT",
|
|
1347
|
+
replacements: {
|
|
1348
|
+
ancestor: parentId,
|
|
1349
|
+
descendant: target,
|
|
1350
|
+
type: subKey
|
|
1351
|
+
},
|
|
1352
|
+
transaction: transaction2
|
|
1353
|
+
}
|
|
1354
|
+
);
|
|
1355
|
+
if (!(ok == null ? void 0 : ok.length)) {
|
|
1356
|
+
throw new Error("flowModels:attach position target is not a sibling under the same parent/subKey");
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
await this.clearXUidPathCache(modelUid, transaction2);
|
|
1360
|
+
await modelInstance.update(
|
|
1361
|
+
{
|
|
1362
|
+
options: {
|
|
1363
|
+
...modelInstance.get("options"),
|
|
1364
|
+
parentId,
|
|
1365
|
+
parent: parentId,
|
|
1366
|
+
subKey,
|
|
1367
|
+
subType
|
|
1368
|
+
}
|
|
1369
|
+
},
|
|
1370
|
+
{ transaction: transaction2, hooks: false }
|
|
1371
|
+
);
|
|
1372
|
+
await this.insertSingleNode(
|
|
1373
|
+
{
|
|
1374
|
+
uid: modelUid,
|
|
1375
|
+
name: modelUid,
|
|
1376
|
+
childOptions: {
|
|
1377
|
+
parentUid: parentId,
|
|
1378
|
+
type: subKey,
|
|
1379
|
+
position
|
|
1380
|
+
}
|
|
1381
|
+
},
|
|
1382
|
+
{ transaction: transaction2, removeParentsIfNoChildren: false }
|
|
1383
|
+
);
|
|
1384
|
+
return await this.findModelById(modelUid, { transaction: transaction2, includeAsyncNode: true });
|
|
1385
|
+
}
|
|
1139
1386
|
async move(options) {
|
|
1140
1387
|
const { sourceId, targetId, position } = options;
|
|
1141
1388
|
return await this.insertAdjacent(position === "after" ? "afterEnd" : "beforeBegin", targetId, {
|
|
@@ -1200,6 +1447,9 @@ __decorateClass([
|
|
|
1200
1447
|
__decorateClass([
|
|
1201
1448
|
transaction()
|
|
1202
1449
|
], _FlowModelRepository.prototype, "upsertModel", 1);
|
|
1450
|
+
__decorateClass([
|
|
1451
|
+
transaction()
|
|
1452
|
+
], _FlowModelRepository.prototype, "attach", 1);
|
|
1203
1453
|
let FlowModelRepository = _FlowModelRepository;
|
|
1204
1454
|
var repository_default = FlowModelRepository;
|
|
1205
1455
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/server/server.js
CHANGED
|
@@ -127,15 +127,34 @@ class PluginUISchemaStorageServer extends import_server.Plugin {
|
|
|
127
127
|
name: "flowModels",
|
|
128
128
|
actions: {
|
|
129
129
|
findOne: async (ctx, next) => {
|
|
130
|
-
const { uid: uid2, parentId, subKey } = ctx.action.params;
|
|
130
|
+
const { uid: uid2, parentId, subKey, includeAsyncNode = false } = ctx.action.params;
|
|
131
131
|
const repository = ctx.db.getRepository("flowModels");
|
|
132
132
|
if (uid2) {
|
|
133
|
-
ctx.body = await repository.findModelById(uid2);
|
|
133
|
+
ctx.body = await repository.findModelById(uid2, { includeAsyncNode });
|
|
134
134
|
} else if (parentId) {
|
|
135
|
-
ctx.body = await repository.findModelByParentId(parentId, { subKey });
|
|
135
|
+
ctx.body = await repository.findModelByParentId(parentId, { subKey, includeAsyncNode });
|
|
136
136
|
}
|
|
137
137
|
await next();
|
|
138
138
|
},
|
|
139
|
+
duplicate: async (ctx, next) => {
|
|
140
|
+
const { uid: uid2 } = ctx.action.params;
|
|
141
|
+
const repository = ctx.db.getRepository("flowModels");
|
|
142
|
+
const duplicated = await repository.duplicate(uid2);
|
|
143
|
+
ctx.body = duplicated;
|
|
144
|
+
await next();
|
|
145
|
+
},
|
|
146
|
+
attach: async (ctx, next) => {
|
|
147
|
+
const { uid: uid2, parentId, subKey, subType, position } = ctx.action.params;
|
|
148
|
+
const repository = ctx.db.getRepository("flowModels");
|
|
149
|
+
const attached = await repository.attach(String(uid2 || "").trim(), {
|
|
150
|
+
parentId: String(parentId || "").trim(),
|
|
151
|
+
subKey: String(subKey || "").trim(),
|
|
152
|
+
subType,
|
|
153
|
+
position
|
|
154
|
+
});
|
|
155
|
+
ctx.body = attached;
|
|
156
|
+
await next();
|
|
157
|
+
},
|
|
139
158
|
move: async (ctx, next) => {
|
|
140
159
|
const { sourceId, targetId, position } = ctx.action.params;
|
|
141
160
|
const repository = ctx.db.getRepository("flowModels");
|
|
@@ -78,14 +78,18 @@ async function replacePlaceholders(input, ctx) {
|
|
|
78
78
|
async function evaluate(expr, ctx) {
|
|
79
79
|
try {
|
|
80
80
|
const raw = expr.trim();
|
|
81
|
-
const dotOnly = raw.match(
|
|
81
|
+
const dotOnly = raw.match(
|
|
82
|
+
/^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\.([a-zA-Z_$][a-zA-Z0-9_$-]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$-]*)*))?$/
|
|
83
|
+
);
|
|
82
84
|
if (dotOnly) {
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const first = segs.shift();
|
|
85
|
+
const first = dotOnly[1];
|
|
86
|
+
const rest = dotOnly[2];
|
|
86
87
|
const base = await ctx[first];
|
|
87
|
-
if (!
|
|
88
|
-
|
|
88
|
+
if (!rest) return base;
|
|
89
|
+
const resolved = await asyncGetValuesByPath(base, rest);
|
|
90
|
+
if (typeof resolved !== "undefined" || !rest.includes("-")) {
|
|
91
|
+
return resolved;
|
|
92
|
+
}
|
|
89
93
|
}
|
|
90
94
|
const transformed = preprocessExpression(raw);
|
|
91
95
|
const compartment = new Compartment({
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
type FilterTargetKey = string | string[] | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* 为了:
|
|
12
|
+
* - 关联加载/缓存:fields 模式下确保包含主键
|
|
13
|
+
* - filterByTk 为数组时:尽量包含 filterTargetKey,以便按输入顺序对齐结果
|
|
14
|
+
*
|
|
15
|
+
* 该函数只返回“建议追加”的 key 字段(不会决定是否追加,由调用方根据是否启用 fields 决定)。
|
|
16
|
+
*/
|
|
17
|
+
export declare function getExtraKeyFieldsForSelect(filterByTk: unknown, options: {
|
|
18
|
+
filterTargetKey?: FilterTargetKey;
|
|
19
|
+
pkAttr?: string;
|
|
20
|
+
pkIsValid?: boolean;
|
|
21
|
+
rawAttributes?: Record<string, unknown>;
|
|
22
|
+
}): string[];
|
|
23
|
+
export declare function mergeFieldsWithExtras(fields?: string[], extras?: string[]): string[] | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* 根据 filterByTk 类型(单值/数组)查询并返回 JSON 数据:
|
|
26
|
+
* - 单值:返回 object | undefined
|
|
27
|
+
* - 数组:返回 array(空数组时返回 [],不会退化为无条件查询)
|
|
28
|
+
*/
|
|
29
|
+
export declare function fetchRecordOrRecordsJson(repo: any, params: {
|
|
30
|
+
filterByTk: unknown;
|
|
31
|
+
preferFullRecord?: boolean;
|
|
32
|
+
fields?: string[];
|
|
33
|
+
appends?: string[];
|
|
34
|
+
filterTargetKey?: FilterTargetKey;
|
|
35
|
+
pkAttr?: string;
|
|
36
|
+
pkIsValid?: boolean;
|
|
37
|
+
}): Promise<unknown>;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var records_exports = {};
|
|
28
|
+
__export(records_exports, {
|
|
29
|
+
fetchRecordOrRecordsJson: () => fetchRecordOrRecordsJson,
|
|
30
|
+
getExtraKeyFieldsForSelect: () => getExtraKeyFieldsForSelect,
|
|
31
|
+
mergeFieldsWithExtras: () => mergeFieldsWithExtras
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(records_exports);
|
|
34
|
+
function uniqStrings(list) {
|
|
35
|
+
return Array.from(new Set(list));
|
|
36
|
+
}
|
|
37
|
+
function isPrimitiveTkArray(arr) {
|
|
38
|
+
return arr.every((v) => typeof v === "string" || typeof v === "number");
|
|
39
|
+
}
|
|
40
|
+
function getOrderKey(options) {
|
|
41
|
+
if (typeof options.filterTargetKey === "string") return options.filterTargetKey;
|
|
42
|
+
if (options.pkIsValid && options.pkAttr) return options.pkAttr;
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
function getExtraKeyFieldsForSelect(filterByTk, options) {
|
|
46
|
+
const extra = [];
|
|
47
|
+
if (options.pkIsValid && options.pkAttr) {
|
|
48
|
+
extra.push(options.pkAttr);
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(filterByTk) && filterByTk.length > 0) {
|
|
51
|
+
const tkKeys = typeof options.filterTargetKey === "string" ? [options.filterTargetKey] : Array.isArray(options.filterTargetKey) ? options.filterTargetKey : [];
|
|
52
|
+
if (options.rawAttributes) {
|
|
53
|
+
for (const k of tkKeys) {
|
|
54
|
+
if (k && Object.prototype.hasOwnProperty.call(options.rawAttributes, k)) {
|
|
55
|
+
extra.push(k);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return uniqStrings(extra);
|
|
61
|
+
}
|
|
62
|
+
function mergeFieldsWithExtras(fields, extras = []) {
|
|
63
|
+
if (!Array.isArray(fields) || fields.length === 0 || extras.length === 0) return fields;
|
|
64
|
+
return uniqStrings([...fields, ...extras]);
|
|
65
|
+
}
|
|
66
|
+
function toJsonArray(rows) {
|
|
67
|
+
if (!Array.isArray(rows)) return [];
|
|
68
|
+
return rows.map((r) => (r == null ? void 0 : r.toJSON) ? r.toJSON() : r);
|
|
69
|
+
}
|
|
70
|
+
function reorderRecordsByFilterByTk(records, filterByTk, options) {
|
|
71
|
+
if (!Array.isArray(filterByTk) || filterByTk.length === 0) return records;
|
|
72
|
+
if (!isPrimitiveTkArray(filterByTk)) return records;
|
|
73
|
+
const orderKey = getOrderKey(options);
|
|
74
|
+
if (!orderKey) return records;
|
|
75
|
+
const map = /* @__PURE__ */ new Map();
|
|
76
|
+
for (const rec of records || []) {
|
|
77
|
+
const k = rec == null ? void 0 : rec[orderKey];
|
|
78
|
+
if (typeof k !== "undefined" && k !== null) {
|
|
79
|
+
map.set(String(k), rec);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const ordered = [];
|
|
83
|
+
const used = /* @__PURE__ */ new Set();
|
|
84
|
+
for (const tk of filterByTk) {
|
|
85
|
+
const k = String(tk);
|
|
86
|
+
const rec = map.get(k);
|
|
87
|
+
if (typeof rec !== "undefined") {
|
|
88
|
+
ordered.push(rec);
|
|
89
|
+
used.add(k);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const rec of records || []) {
|
|
93
|
+
const k = rec == null ? void 0 : rec[orderKey];
|
|
94
|
+
const ks = typeof k === "undefined" || k === null ? void 0 : String(k);
|
|
95
|
+
if (!ks || used.has(ks)) continue;
|
|
96
|
+
ordered.push(rec);
|
|
97
|
+
}
|
|
98
|
+
return ordered;
|
|
99
|
+
}
|
|
100
|
+
async function fetchRecordOrRecordsJson(repo, params) {
|
|
101
|
+
const { filterByTk, preferFullRecord, fields, appends } = params;
|
|
102
|
+
if (Array.isArray(filterByTk)) {
|
|
103
|
+
if (filterByTk.length === 0) return [];
|
|
104
|
+
const rows = await repo.find(
|
|
105
|
+
preferFullRecord ? { filterByTk } : { filterByTk, fields, appends }
|
|
106
|
+
);
|
|
107
|
+
const jsonArr = toJsonArray(rows);
|
|
108
|
+
return reorderRecordsByFilterByTk(jsonArr, filterByTk, params);
|
|
109
|
+
}
|
|
110
|
+
const rec = await repo.findOne(
|
|
111
|
+
preferFullRecord ? { filterByTk } : { filterByTk, fields, appends }
|
|
112
|
+
);
|
|
113
|
+
return rec ? rec.toJSON() : void 0;
|
|
114
|
+
}
|
|
115
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
116
|
+
0 && (module.exports = {
|
|
117
|
+
fetchRecordOrRecordsJson,
|
|
118
|
+
getExtraKeyFieldsForSelect,
|
|
119
|
+
mergeFieldsWithExtras
|
|
120
|
+
});
|
|
@@ -39,4 +39,14 @@ declare class VariableRegistry {
|
|
|
39
39
|
attachUsedVariables(ctx: HttpRequestContext, koaCtx: ResourcerContext, template: JSONValue, contextParams: any): Promise<void>;
|
|
40
40
|
}
|
|
41
41
|
export declare const variables: VariableRegistry;
|
|
42
|
+
/** 仅测试使用:重置变量注册表为内置默认集 */
|
|
43
|
+
/**
|
|
44
|
+
* 从使用路径推断查询所需的 fields 与 appends。
|
|
45
|
+
* @param paths 使用到的子路径数组
|
|
46
|
+
* @param params 显式参数(仅用于兼容签名)
|
|
47
|
+
*/
|
|
48
|
+
export declare function inferSelectsFromUsage(paths?: string[], _params?: unknown): {
|
|
49
|
+
generatedAppends?: string[];
|
|
50
|
+
generatedFields?: string[];
|
|
51
|
+
};
|
|
42
52
|
export {};
|