@nocobase/plugin-workflow 1.6.0-alpha.2 → 1.6.0-alpha.21
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/client/4147131201cde30c.js +10 -0
- package/dist/client/4a2b78cd09ce676a.js +10 -0
- package/dist/client/FlowContext.d.ts +2 -0
- package/dist/client/WorkflowTasks.d.ts +17 -0
- package/dist/client/e73d2e9169520d3e.js +10 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.js +1 -1
- package/dist/client/nodes/calculation.d.ts +3 -2
- package/dist/client/nodes/condition.d.ts +1 -0
- package/dist/client/nodes/create.d.ts +3 -2
- package/dist/client/nodes/destroy.d.ts +2 -0
- package/dist/client/nodes/end.d.ts +2 -0
- package/dist/client/nodes/index.d.ts +1 -0
- package/dist/client/nodes/output.d.ts +31 -0
- package/dist/client/nodes/query.d.ts +5 -4
- package/dist/client/nodes/update.d.ts +3 -2
- package/dist/client/triggers/schedule/ScheduleModes.d.ts +5 -2
- package/dist/client/triggers/schedule/index.d.ts +2 -0
- package/dist/client/variable.d.ts +17 -6
- package/dist/externalVersion.js +11 -11
- package/dist/locale/en-US.json +3 -1
- package/dist/locale/zh-CN.json +11 -7
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/lru-cache/package.json +1 -1
- package/dist/server/Plugin.d.ts +9 -6
- package/dist/server/Plugin.js +116 -45
- package/dist/server/Processor.d.ts +5 -0
- package/dist/server/Processor.js +15 -6
- package/dist/server/actions/workflows.js +5 -2
- package/dist/server/collections/executions.js +9 -0
- package/dist/server/collections/flow_nodes.js +1 -0
- package/dist/server/collections/jobs.js +1 -0
- package/dist/server/collections/workflows.js +1 -0
- package/dist/server/instructions/CreateInstruction.js +1 -1
- package/dist/server/instructions/DestroyInstruction.js +1 -1
- package/dist/server/instructions/UpdateInstruction.js +1 -1
- package/dist/server/triggers/CollectionTrigger.d.ts +6 -6
- package/dist/server/triggers/CollectionTrigger.js +51 -31
- package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.d.ts +5 -1
- package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.js +53 -14
- package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.d.ts +1 -0
- package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.js +3 -0
- package/dist/server/triggers/ScheduleTrigger/index.d.ts +2 -2
- package/dist/server/triggers/ScheduleTrigger/index.js +21 -3
- package/dist/server/triggers/index.d.ts +4 -1
- package/package.json +3 -3
- package/dist/client/923.index.js +0 -10
- package/dist/client/929.index.js +0 -10
- package/dist/client/999.index.js +0 -10
- /package/dist/client/{383.index.js → 739d458621edf81f.js} +0 -0
package/dist/server/Plugin.js
CHANGED
|
@@ -41,6 +41,7 @@ __export(Plugin_exports, {
|
|
|
41
41
|
module.exports = __toCommonJS(Plugin_exports);
|
|
42
42
|
var import_path = __toESM(require("path"));
|
|
43
43
|
var import_crypto = require("crypto");
|
|
44
|
+
var import_sequelize = require("sequelize");
|
|
44
45
|
var import_lru_cache = __toESM(require("lru-cache"));
|
|
45
46
|
var import_database = require("@nocobase/database");
|
|
46
47
|
var import_server = require("@nocobase/server");
|
|
@@ -126,7 +127,7 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
126
127
|
/**
|
|
127
128
|
* @experimental
|
|
128
129
|
*/
|
|
129
|
-
getLogger(workflowId) {
|
|
130
|
+
getLogger(workflowId = "dispatcher") {
|
|
130
131
|
const now = /* @__PURE__ */ new Date();
|
|
131
132
|
const date = `${now.getFullYear()}-${`0${now.getMonth() + 1}`.slice(-2)}-${`0${now.getDate()}`.slice(-2)}`;
|
|
132
133
|
const key = `${date}-${workflowId}}`;
|
|
@@ -256,7 +257,6 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
256
257
|
(model, { transaction }) => this.toggle(model, false, { transaction })
|
|
257
258
|
);
|
|
258
259
|
this.app.on("afterStart", async () => {
|
|
259
|
-
this.app.setMaintainingMessage("check for not started executions");
|
|
260
260
|
this.ready = true;
|
|
261
261
|
const collection = db.getCollection("workflows");
|
|
262
262
|
const workflows = await collection.repository.find({
|
|
@@ -266,8 +266,14 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
266
266
|
this.toggle(workflow, true, { silent: true });
|
|
267
267
|
});
|
|
268
268
|
this.checker = setInterval(() => {
|
|
269
|
+
this.getLogger("dispatcher").info(`(cycling) check for queueing executions`);
|
|
269
270
|
this.dispatch();
|
|
270
271
|
}, 3e5);
|
|
272
|
+
this.app.on("workflow:dispatch", () => {
|
|
273
|
+
this.app.logger.info("workflow:dispatch");
|
|
274
|
+
this.dispatch();
|
|
275
|
+
});
|
|
276
|
+
this.getLogger("dispatcher").info("(starting) check for queueing executions");
|
|
271
277
|
this.dispatch();
|
|
272
278
|
});
|
|
273
279
|
this.app.on("beforeStop", async () => {
|
|
@@ -323,10 +329,19 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
323
329
|
logger.debug(`ignored event data:`, context);
|
|
324
330
|
return;
|
|
325
331
|
}
|
|
326
|
-
if (!options.manually && !workflow.enabled) {
|
|
332
|
+
if (!options.force && !options.manually && !workflow.enabled) {
|
|
327
333
|
logger.warn(`workflow ${workflow.id} is not enabled, event will be ignored`);
|
|
328
334
|
return;
|
|
329
335
|
}
|
|
336
|
+
const duplicated = this.events.find(([w, c, { eventKey }]) => {
|
|
337
|
+
if (eventKey && options.eventKey) {
|
|
338
|
+
return eventKey === options.eventKey;
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
if (duplicated) {
|
|
342
|
+
logger.warn(`event of workflow ${workflow.id} is duplicated (${options.eventKey}), event will be ignored`);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
330
345
|
if (context == null) {
|
|
331
346
|
logger.warn(`workflow ${workflow.id} event data context is null, event will be ignored`);
|
|
332
347
|
return;
|
|
@@ -340,9 +355,10 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
340
355
|
logger.info(`new event triggered, now events: ${this.events.length}`);
|
|
341
356
|
logger.debug(`event data:`, { context });
|
|
342
357
|
if (this.events.length > 1) {
|
|
358
|
+
logger.info(`new event is pending to be prepared after previous preparation is finished`);
|
|
343
359
|
return;
|
|
344
360
|
}
|
|
345
|
-
|
|
361
|
+
setImmediate(this.prepare);
|
|
346
362
|
}
|
|
347
363
|
async triggerSync(workflow, context, { deferred, ...options } = {}) {
|
|
348
364
|
let execution;
|
|
@@ -367,33 +383,63 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
367
383
|
`execution (${job.execution.id}) resuming from job (${job.id}) added to pending list`
|
|
368
384
|
);
|
|
369
385
|
this.pending.push([job.execution, job]);
|
|
386
|
+
if (this.executing) {
|
|
387
|
+
await this.executing;
|
|
388
|
+
}
|
|
370
389
|
this.dispatch();
|
|
371
390
|
}
|
|
372
391
|
/**
|
|
373
392
|
* Start a deferred execution
|
|
374
393
|
* @experimental
|
|
375
394
|
*/
|
|
376
|
-
start(execution) {
|
|
395
|
+
async start(execution) {
|
|
377
396
|
if (execution.status !== import_constants.EXECUTION_STATUS.STARTED) {
|
|
378
397
|
return;
|
|
379
398
|
}
|
|
399
|
+
this.getLogger(execution.workflowId).info(`starting deferred execution (${execution.id})`);
|
|
380
400
|
this.pending.push([execution]);
|
|
401
|
+
if (this.executing) {
|
|
402
|
+
await this.executing;
|
|
403
|
+
}
|
|
381
404
|
this.dispatch();
|
|
382
405
|
}
|
|
383
|
-
|
|
384
|
-
|
|
406
|
+
async validateEvent(workflow, context, options) {
|
|
407
|
+
const trigger = this.triggers.get(workflow.type);
|
|
408
|
+
const triggerValid = await trigger.validateEvent(workflow, context, options);
|
|
409
|
+
if (!triggerValid) {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
const { stack } = options;
|
|
413
|
+
let valid = true;
|
|
414
|
+
if ((stack == null ? void 0 : stack.length) > 0) {
|
|
415
|
+
const existed = await workflow.countExecutions({
|
|
416
|
+
where: {
|
|
417
|
+
id: stack
|
|
418
|
+
},
|
|
419
|
+
transaction: options.transaction
|
|
420
|
+
});
|
|
421
|
+
const limitCount = workflow.options.stackLimit || 1;
|
|
422
|
+
if (existed >= limitCount) {
|
|
423
|
+
this.getLogger(workflow.id).warn(
|
|
424
|
+
`workflow ${workflow.id} has already been triggered in stacks executions (${stack}), and max call coont is ${limitCount}, newly triggering will be skipped.`
|
|
425
|
+
);
|
|
426
|
+
valid = false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return valid;
|
|
385
430
|
}
|
|
386
431
|
async createExecution(workflow, context, options) {
|
|
432
|
+
var _a;
|
|
387
433
|
const { deferred } = options;
|
|
388
434
|
const transaction = await this.useDataSourceTransaction("main", options.transaction, true);
|
|
389
435
|
const sameTransaction = options.transaction === transaction;
|
|
390
|
-
const
|
|
391
|
-
const valid = await trigger.validateEvent(workflow, context, { ...options, transaction });
|
|
436
|
+
const valid = await this.validateEvent(workflow, context, { ...options, transaction });
|
|
392
437
|
if (!valid) {
|
|
393
438
|
if (!sameTransaction) {
|
|
394
439
|
await transaction.commit();
|
|
395
440
|
}
|
|
396
|
-
|
|
441
|
+
(_a = options.onTriggerFail) == null ? void 0 : _a.call(options, workflow, context, options);
|
|
442
|
+
return Promise.reject(new Error("event is not valid"));
|
|
397
443
|
}
|
|
398
444
|
let execution;
|
|
399
445
|
try {
|
|
@@ -402,6 +448,7 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
402
448
|
context,
|
|
403
449
|
key: workflow.key,
|
|
404
450
|
eventKey: options.eventKey ?? (0, import_crypto.randomUUID)(),
|
|
451
|
+
stack: options.stack,
|
|
405
452
|
status: deferred ? import_constants.EXECUTION_STATUS.STARTED : import_constants.EXECUTION_STATUS.QUEUEING
|
|
406
453
|
},
|
|
407
454
|
{ transaction }
|
|
@@ -441,7 +488,7 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
441
488
|
const event = this.events.shift();
|
|
442
489
|
this.eventsCount = this.events.length;
|
|
443
490
|
if (!event) {
|
|
444
|
-
this.getLogger("dispatcher").
|
|
491
|
+
this.getLogger("dispatcher").info(`events queue is empty, no need to prepare`);
|
|
445
492
|
return;
|
|
446
493
|
}
|
|
447
494
|
const logger = this.getLogger(event[0].id);
|
|
@@ -451,12 +498,16 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
451
498
|
if ((execution == null ? void 0 : execution.status) === import_constants.EXECUTION_STATUS.QUEUEING && !this.executing && !this.pending.length) {
|
|
452
499
|
this.pending.push([execution]);
|
|
453
500
|
}
|
|
454
|
-
} catch (
|
|
455
|
-
logger.error(`failed to create execution
|
|
501
|
+
} catch (error) {
|
|
502
|
+
logger.error(`failed to create execution:`, { error });
|
|
456
503
|
}
|
|
457
504
|
if (this.events.length) {
|
|
458
505
|
await this.prepare();
|
|
459
506
|
} else {
|
|
507
|
+
this.getLogger("dispatcher").info("no more events need to be prepared, dispatching...");
|
|
508
|
+
if (this.executing) {
|
|
509
|
+
await this.executing;
|
|
510
|
+
}
|
|
460
511
|
this.dispatch();
|
|
461
512
|
}
|
|
462
513
|
};
|
|
@@ -474,58 +525,78 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
474
525
|
}
|
|
475
526
|
this.executing = (async () => {
|
|
476
527
|
let next = null;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
"workflow.enabled": true,
|
|
486
|
-
"workflow.id": {
|
|
487
|
-
[import_database.Op.not]: null
|
|
488
|
-
}
|
|
528
|
+
if (this.pending.length) {
|
|
529
|
+
next = this.pending.shift();
|
|
530
|
+
this.getLogger(next[0].workflowId).info(`pending execution (${next[0].id}) ready to process`);
|
|
531
|
+
} else {
|
|
532
|
+
try {
|
|
533
|
+
await this.db.sequelize.transaction(
|
|
534
|
+
{
|
|
535
|
+
isolationLevel: this.db.options.dialect === "sqlite" ? [][0] : import_sequelize.Transaction.ISOLATION_LEVELS.REPEATABLE_READ
|
|
489
536
|
},
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
537
|
+
async (transaction) => {
|
|
538
|
+
const execution = await this.db.getRepository("executions").findOne({
|
|
539
|
+
filter: {
|
|
540
|
+
status: import_constants.EXECUTION_STATUS.QUEUEING,
|
|
541
|
+
"workflow.enabled": true
|
|
542
|
+
},
|
|
543
|
+
sort: "id",
|
|
544
|
+
transaction
|
|
545
|
+
});
|
|
546
|
+
if (execution) {
|
|
547
|
+
this.getLogger(execution.workflowId).info(`execution (${execution.id}) fetched from db`);
|
|
548
|
+
await execution.update(
|
|
549
|
+
{
|
|
550
|
+
status: import_constants.EXECUTION_STATUS.STARTED
|
|
551
|
+
},
|
|
552
|
+
{ transaction }
|
|
553
|
+
);
|
|
554
|
+
execution.workflow = this.enabledCache.get(execution.workflowId);
|
|
555
|
+
next = [execution];
|
|
556
|
+
} else {
|
|
557
|
+
this.getLogger("dispatcher").info(`no execution in db queued to process`);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
);
|
|
561
|
+
} catch (error) {
|
|
562
|
+
this.getLogger("dispatcher").error(`fetching execution from db failed: ${error.message}`, { error });
|
|
505
563
|
}
|
|
506
564
|
}
|
|
565
|
+
if (next) {
|
|
566
|
+
await this.process(...next);
|
|
567
|
+
}
|
|
568
|
+
this.executing = null;
|
|
569
|
+
if (next || this.pending.length) {
|
|
570
|
+
this.getLogger("dispatcher").info(`last process finished, will do another dispatch`);
|
|
571
|
+
this.dispatch();
|
|
572
|
+
}
|
|
507
573
|
})();
|
|
508
574
|
}
|
|
575
|
+
createProcessor(execution, options = {}) {
|
|
576
|
+
return new import_Processor.default(execution, { ...options, plugin: this });
|
|
577
|
+
}
|
|
509
578
|
async process(execution, job, options = {}) {
|
|
510
579
|
var _a, _b;
|
|
580
|
+
const logger = this.getLogger(execution.workflowId);
|
|
511
581
|
if (execution.status === import_constants.EXECUTION_STATUS.QUEUEING) {
|
|
512
|
-
await
|
|
582
|
+
const transaction = await this.useDataSourceTransaction("main", options.transaction);
|
|
583
|
+
await execution.update({ status: import_constants.EXECUTION_STATUS.STARTED }, { transaction });
|
|
584
|
+
logger.info(`queueing execution (${execution.id}) from pending list updated to started`);
|
|
513
585
|
}
|
|
514
|
-
const logger = this.getLogger(execution.workflowId);
|
|
515
586
|
const processor = this.createProcessor(execution, options);
|
|
516
587
|
logger.info(`execution (${execution.id}) ${job ? "resuming" : "starting"}...`);
|
|
517
588
|
try {
|
|
518
589
|
await (job ? processor.resume(job) : processor.start());
|
|
519
590
|
logger.info(`execution (${execution.id}) finished with status: ${execution.status}`, { execution });
|
|
520
591
|
if (execution.status && ((_b = (_a = execution.workflow.options) == null ? void 0 : _a.deleteExecutionOnStatus) == null ? void 0 : _b.includes(execution.status))) {
|
|
521
|
-
await execution.destroy();
|
|
592
|
+
await execution.destroy({ transaction: processor.mainTransaction });
|
|
522
593
|
}
|
|
523
594
|
} catch (err) {
|
|
524
595
|
logger.error(`execution (${execution.id}) error: ${err.message}`, err);
|
|
525
596
|
}
|
|
526
597
|
return processor;
|
|
527
598
|
}
|
|
528
|
-
async execute(workflow,
|
|
599
|
+
async execute(workflow, values, options = {}) {
|
|
529
600
|
const trigger = this.triggers.get(workflow.type);
|
|
530
601
|
if (!trigger) {
|
|
531
602
|
throw new Error(`trigger type "${workflow.type}" of workflow ${workflow.id} is not registered`);
|
|
@@ -533,7 +604,7 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
533
604
|
if (!trigger.execute) {
|
|
534
605
|
throw new Error(`"execute" method of trigger ${workflow.type} is not implemented`);
|
|
535
606
|
}
|
|
536
|
-
return trigger.execute(workflow,
|
|
607
|
+
return trigger.execute(workflow, values, options);
|
|
537
608
|
}
|
|
538
609
|
/**
|
|
539
610
|
* @experimental
|
|
@@ -32,6 +32,10 @@ export default class Processor {
|
|
|
32
32
|
* @experimental
|
|
33
33
|
*/
|
|
34
34
|
transaction: Transaction;
|
|
35
|
+
/**
|
|
36
|
+
* @experimental
|
|
37
|
+
*/
|
|
38
|
+
mainTransaction: Transaction;
|
|
35
39
|
/**
|
|
36
40
|
* @experimental
|
|
37
41
|
*/
|
|
@@ -105,6 +109,7 @@ export default class Processor {
|
|
|
105
109
|
};
|
|
106
110
|
$system: {};
|
|
107
111
|
$scopes: {};
|
|
112
|
+
$env: {};
|
|
108
113
|
};
|
|
109
114
|
/**
|
|
110
115
|
* @experimental
|
package/dist/server/Processor.js
CHANGED
|
@@ -66,6 +66,10 @@ class Processor {
|
|
|
66
66
|
* @experimental
|
|
67
67
|
*/
|
|
68
68
|
transaction;
|
|
69
|
+
/**
|
|
70
|
+
* @experimental
|
|
71
|
+
*/
|
|
72
|
+
mainTransaction;
|
|
69
73
|
/**
|
|
70
74
|
* @experimental
|
|
71
75
|
*/
|
|
@@ -111,11 +115,12 @@ class Processor {
|
|
|
111
115
|
async prepare() {
|
|
112
116
|
const {
|
|
113
117
|
execution,
|
|
114
|
-
transaction,
|
|
115
118
|
options: { plugin }
|
|
116
119
|
} = this;
|
|
120
|
+
this.mainTransaction = plugin.useDataSourceTransaction("main", this.transaction);
|
|
121
|
+
const transaction = this.mainTransaction;
|
|
117
122
|
if (!execution.workflow) {
|
|
118
|
-
execution.workflow = plugin.enabledCache.get(execution.workflowId);
|
|
123
|
+
execution.workflow = plugin.enabledCache.get(execution.workflowId) || await execution.getWorkflow({ transaction });
|
|
119
124
|
}
|
|
120
125
|
const nodes = await execution.workflow.getNodes({ transaction });
|
|
121
126
|
this.makeNodes(nodes);
|
|
@@ -154,7 +159,7 @@ class Processor {
|
|
|
154
159
|
this.logger.debug(`config of node`, { data: node.config });
|
|
155
160
|
job = await instruction(node, prevJob, this);
|
|
156
161
|
if (!job) {
|
|
157
|
-
return
|
|
162
|
+
return this.exit();
|
|
158
163
|
}
|
|
159
164
|
} catch (err) {
|
|
160
165
|
this.logger.error(
|
|
@@ -227,7 +232,10 @@ class Processor {
|
|
|
227
232
|
async exit(s) {
|
|
228
233
|
if (typeof s === "number") {
|
|
229
234
|
const status = this.constructor.StatusMap[s] ?? Math.sign(s);
|
|
230
|
-
await this.execution.update({ status }, { transaction: this.
|
|
235
|
+
await this.execution.update({ status }, { transaction: this.mainTransaction });
|
|
236
|
+
}
|
|
237
|
+
if (this.mainTransaction && this.mainTransaction !== this.transaction) {
|
|
238
|
+
await this.mainTransaction.commit();
|
|
231
239
|
}
|
|
232
240
|
this.logger.info(`execution (${this.execution.id}) exiting with status ${this.execution.status}`);
|
|
233
241
|
return null;
|
|
@@ -238,7 +246,7 @@ class Processor {
|
|
|
238
246
|
*/
|
|
239
247
|
async saveJob(payload) {
|
|
240
248
|
const { database } = this.execution.constructor;
|
|
241
|
-
const { transaction } = this;
|
|
249
|
+
const { mainTransaction: transaction } = this;
|
|
242
250
|
const { model } = database.getCollection("jobs");
|
|
243
251
|
let job;
|
|
244
252
|
if (payload instanceof model) {
|
|
@@ -361,7 +369,8 @@ class Processor {
|
|
|
361
369
|
$context: this.execution.context,
|
|
362
370
|
$jobsMapByNodeKey: this.jobsMapByNodeKey,
|
|
363
371
|
$system: systemFns,
|
|
364
|
-
$scopes
|
|
372
|
+
$scopes,
|
|
373
|
+
$env: this.options.plugin.app.environment.getVariables()
|
|
365
374
|
};
|
|
366
375
|
}
|
|
367
376
|
/**
|
|
@@ -121,7 +121,10 @@ async function trigger(context, next) {
|
|
|
121
121
|
}
|
|
122
122
|
async function execute(context, next) {
|
|
123
123
|
const plugin = context.app.pm.get(import_Plugin.default);
|
|
124
|
-
const { filterByTk, autoRevision } = context.action.params;
|
|
124
|
+
const { filterByTk, values, autoRevision } = context.action.params;
|
|
125
|
+
if (!values) {
|
|
126
|
+
return context.throw(400, "values is required");
|
|
127
|
+
}
|
|
125
128
|
if (!filterByTk) {
|
|
126
129
|
return context.throw(400, "filterByTk is required");
|
|
127
130
|
}
|
|
@@ -137,7 +140,7 @@ async function execute(context, next) {
|
|
|
137
140
|
const { executed } = workflow;
|
|
138
141
|
let processor;
|
|
139
142
|
try {
|
|
140
|
-
processor = await plugin.execute(workflow,
|
|
143
|
+
processor = await plugin.execute(workflow, values, { manually: true });
|
|
141
144
|
if (!processor) {
|
|
142
145
|
return context.throw(400, "workflow not triggered");
|
|
143
146
|
}
|
|
@@ -33,6 +33,7 @@ var executions_default = {
|
|
|
33
33
|
dumpRules: {
|
|
34
34
|
group: "log"
|
|
35
35
|
},
|
|
36
|
+
migrationRules: ["schema-only"],
|
|
36
37
|
name: "executions",
|
|
37
38
|
shared: true,
|
|
38
39
|
fields: [
|
|
@@ -61,6 +62,14 @@ var executions_default = {
|
|
|
61
62
|
{
|
|
62
63
|
type: "integer",
|
|
63
64
|
name: "status"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: "json",
|
|
68
|
+
name: "stack"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: "json",
|
|
72
|
+
name: "output"
|
|
64
73
|
}
|
|
65
74
|
]
|
|
66
75
|
};
|
|
@@ -44,7 +44,7 @@ class CreateInstruction extends import__.Instruction {
|
|
|
44
44
|
const created = await repository.create({
|
|
45
45
|
...options,
|
|
46
46
|
context: {
|
|
47
|
-
stack: Array.from(new Set((processor.execution.
|
|
47
|
+
stack: Array.from(new Set((processor.execution.stack ?? []).concat(processor.execution.id)))
|
|
48
48
|
},
|
|
49
49
|
transaction
|
|
50
50
|
});
|
|
@@ -42,7 +42,7 @@ class DestroyInstruction extends import__.Instruction {
|
|
|
42
42
|
const result = await repository.destroy({
|
|
43
43
|
...options,
|
|
44
44
|
context: {
|
|
45
|
-
stack: Array.from(new Set((processor.execution.
|
|
45
|
+
stack: Array.from(new Set((processor.execution.stack ?? []).concat(processor.execution.id)))
|
|
46
46
|
},
|
|
47
47
|
transaction: this.workflow.useDataSourceTransaction(dataSourceName, processor.transaction)
|
|
48
48
|
});
|
|
@@ -42,7 +42,7 @@ class UpdateInstruction extends import__.Instruction {
|
|
|
42
42
|
const result = await repository.update({
|
|
43
43
|
...options,
|
|
44
44
|
context: {
|
|
45
|
-
stack: Array.from(new Set((processor.execution.
|
|
45
|
+
stack: Array.from(new Set((processor.execution.stack ?? []).concat(processor.execution.id)))
|
|
46
46
|
},
|
|
47
47
|
transaction: this.workflow.useDataSourceTransaction(dataSourceName, processor.transaction)
|
|
48
48
|
});
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import { Model
|
|
9
|
+
import { Model } from '@nocobase/database';
|
|
10
10
|
import Trigger from '.';
|
|
11
11
|
import type { WorkflowModel } from '../types';
|
|
12
12
|
import type { EventOptions } from '../Plugin';
|
|
13
|
-
import { Context } from '@nocobase/actions';
|
|
14
13
|
export interface CollectionChangeTriggerConfig {
|
|
15
14
|
collection: string;
|
|
16
15
|
mode: number;
|
|
@@ -19,12 +18,13 @@ export interface CollectionChangeTriggerConfig {
|
|
|
19
18
|
export default class CollectionTrigger extends Trigger {
|
|
20
19
|
events: Map<any, any>;
|
|
21
20
|
private static handler;
|
|
22
|
-
prepare(workflow: WorkflowModel, data: Model | Record<string, any
|
|
21
|
+
prepare(workflow: WorkflowModel, data: Model | Record<string, any> | string | number, options: any): Promise<{
|
|
23
22
|
data: any;
|
|
24
|
-
stack: any;
|
|
25
23
|
}>;
|
|
26
24
|
on(workflow: WorkflowModel): void;
|
|
27
25
|
off(workflow: WorkflowModel): void;
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
execute(workflow: WorkflowModel, values: any, options: EventOptions): Promise<void | import("..").Processor>;
|
|
27
|
+
validateContext(values: any): {
|
|
28
|
+
data: string;
|
|
29
|
+
};
|
|
30
30
|
}
|
|
@@ -74,17 +74,19 @@ class CollectionTrigger extends import__.default {
|
|
|
74
74
|
if (!ctx) {
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
+
const { stack } = options.context ?? {};
|
|
77
78
|
if (workflow.sync) {
|
|
78
79
|
await this.workflow.trigger(workflow, ctx, {
|
|
79
|
-
transaction
|
|
80
|
+
transaction,
|
|
81
|
+
stack
|
|
80
82
|
});
|
|
81
83
|
} else {
|
|
82
84
|
if (transaction) {
|
|
83
85
|
transaction.afterCommit(() => {
|
|
84
|
-
this.workflow.trigger(workflow, ctx);
|
|
86
|
+
this.workflow.trigger(workflow, ctx, { stack });
|
|
85
87
|
});
|
|
86
88
|
} else {
|
|
87
|
-
this.workflow.trigger(workflow, ctx);
|
|
89
|
+
this.workflow.trigger(workflow, ctx, { stack });
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
}
|
|
@@ -95,13 +97,24 @@ class CollectionTrigger extends import__.default {
|
|
|
95
97
|
const collection = collectionManager.getCollection(collectionName);
|
|
96
98
|
const { transaction, context } = options;
|
|
97
99
|
const { repository, filterTargetKey } = collection;
|
|
98
|
-
|
|
100
|
+
let target = data;
|
|
101
|
+
let filterByTk;
|
|
102
|
+
let loadNeeded = false;
|
|
103
|
+
if (target && typeof target === "object") {
|
|
104
|
+
filterByTk = Array.isArray(filterTargetKey) ? (0, import_lodash.pick)(
|
|
105
|
+
target,
|
|
106
|
+
filterTargetKey.sort((a, b) => a.localeCompare(b))
|
|
107
|
+
) : target[filterTargetKey];
|
|
108
|
+
} else {
|
|
109
|
+
filterByTk = target;
|
|
110
|
+
loadNeeded = true;
|
|
111
|
+
}
|
|
112
|
+
if (target instanceof import_database.Model && changed && changed.length && changed.filter((name) => {
|
|
99
113
|
const field = collection.getField(name);
|
|
100
114
|
return field && !["linkTo", "hasOne", "hasMany", "belongsToMany"].includes(field.options.type);
|
|
101
|
-
}).every((name) => !
|
|
115
|
+
}).every((name) => !target.changedWithAssociations(getFieldRawName(collection, name)))) {
|
|
102
116
|
return null;
|
|
103
117
|
}
|
|
104
|
-
const filterByTk = Array.isArray(filterTargetKey) ? (0, import_lodash.pick)(data, filterTargetKey) : { [filterTargetKey]: data[filterTargetKey] };
|
|
105
118
|
if ((0, import_utils.isValidFilter)(condition) && !(mode & MODE_BITMAP.DESTROY)) {
|
|
106
119
|
const count = await repository.count({
|
|
107
120
|
filterByTk,
|
|
@@ -113,22 +126,20 @@ class CollectionTrigger extends import__.default {
|
|
|
113
126
|
return null;
|
|
114
127
|
}
|
|
115
128
|
}
|
|
116
|
-
|
|
117
|
-
if ((appends == null ? void 0 : appends.length) && !(mode & MODE_BITMAP.DESTROY)) {
|
|
129
|
+
if (loadNeeded || (appends == null ? void 0 : appends.length) && !(mode & MODE_BITMAP.DESTROY)) {
|
|
118
130
|
const includeFields = appends.reduce((set, field) => {
|
|
119
131
|
set.add(field.split(".")[0]);
|
|
120
132
|
set.add(field);
|
|
121
133
|
return set;
|
|
122
134
|
}, /* @__PURE__ */ new Set());
|
|
123
|
-
|
|
135
|
+
target = await repository.findOne({
|
|
124
136
|
filterByTk,
|
|
125
137
|
appends: Array.from(includeFields),
|
|
126
138
|
transaction
|
|
127
139
|
});
|
|
128
140
|
}
|
|
129
141
|
return {
|
|
130
|
-
data: (0, import_utils2.toJSON)(
|
|
131
|
-
stack: context == null ? void 0 : context.stack
|
|
142
|
+
data: (0, import_utils2.toJSON)(target)
|
|
132
143
|
};
|
|
133
144
|
}
|
|
134
145
|
on(workflow) {
|
|
@@ -182,26 +193,27 @@ class CollectionTrigger extends import__.default {
|
|
|
182
193
|
}
|
|
183
194
|
}
|
|
184
195
|
}
|
|
185
|
-
async validateEvent(workflow, context, options) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
196
|
+
// async validateEvent(workflow: WorkflowModel, context: any, options: Transactionable): Promise<boolean> {
|
|
197
|
+
// if (context.stack) {
|
|
198
|
+
// const existed = await workflow.countExecutions({
|
|
199
|
+
// where: {
|
|
200
|
+
// id: context.stack,
|
|
201
|
+
// },
|
|
202
|
+
// transaction: options.transaction,
|
|
203
|
+
// });
|
|
204
|
+
// if (existed) {
|
|
205
|
+
// this.workflow
|
|
206
|
+
// .getLogger(workflow.id)
|
|
207
|
+
// .warn(
|
|
208
|
+
// `workflow ${workflow.id} has already been triggered in stack executions (${context.stack}), and newly triggering will be skipped.`,
|
|
209
|
+
// );
|
|
210
|
+
// return false;
|
|
211
|
+
// }
|
|
212
|
+
// }
|
|
213
|
+
// return true;
|
|
214
|
+
// }
|
|
215
|
+
async execute(workflow, values, options) {
|
|
216
|
+
const ctx = await this.prepare(workflow, values == null ? void 0 : values.data, options);
|
|
205
217
|
const [dataSourceName] = (0, import_data_source_manager.parseCollectionName)(workflow.config.collection);
|
|
206
218
|
const { transaction } = options;
|
|
207
219
|
return this.workflow.trigger(workflow, ctx, {
|
|
@@ -209,4 +221,12 @@ class CollectionTrigger extends import__.default {
|
|
|
209
221
|
transaction: this.workflow.useDataSourceTransaction(dataSourceName, transaction)
|
|
210
222
|
});
|
|
211
223
|
}
|
|
224
|
+
validateContext(values) {
|
|
225
|
+
if (!values.data) {
|
|
226
|
+
return {
|
|
227
|
+
data: "Data is required"
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
212
232
|
}
|
|
@@ -30,10 +30,14 @@ export default class DateFieldScheduleTrigger {
|
|
|
30
30
|
constructor(workflow: Plugin);
|
|
31
31
|
reload(): Promise<void>;
|
|
32
32
|
inspect(workflows: WorkflowModel[]): void;
|
|
33
|
-
loadRecordsToSchedule({ config: { collection, limit, startsOn, repeat, endsOn }, allExecuted }: WorkflowModel, currentDate: Date): Promise<import("@nocobase/database").Model<any, any>[]>;
|
|
33
|
+
loadRecordsToSchedule({ id, config: { collection, limit, startsOn, repeat, endsOn }, allExecuted }: WorkflowModel, currentDate: Date): Promise<import("@nocobase/database").Model<any, any>[]>;
|
|
34
34
|
getRecordNextTime(workflow: WorkflowModel, record: any, nextSecond?: boolean): any;
|
|
35
35
|
schedule(workflow: WorkflowModel, record: any, nextTime: any, toggle?: boolean, options?: {}): Promise<void>;
|
|
36
36
|
trigger(workflow: WorkflowModel, record: any, nextTime: any, { transaction }?: Transactionable): Promise<void>;
|
|
37
37
|
on(workflow: WorkflowModel): void;
|
|
38
38
|
off(workflow: WorkflowModel): void;
|
|
39
|
+
execute(workflow: any, values: any, options: any): Promise<void | import("../..").Processor>;
|
|
40
|
+
validateContext(values: any): {
|
|
41
|
+
data: string;
|
|
42
|
+
};
|
|
39
43
|
}
|