@nocobase/plugin-workflow 1.5.0-beta.3 → 1.5.0-beta.30

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.
Files changed (44) hide show
  1. package/dist/client/112c72b90000c81b.js +10 -0
  2. package/dist/client/739d458621edf81f.js +10 -0
  3. package/dist/client/98864c2e0ff69ea1.js +10 -0
  4. package/dist/client/FlowContext.d.ts +2 -0
  5. package/dist/client/components/TriggerCollectionRecordSelect.d.ts +10 -0
  6. package/dist/client/components/index.d.ts +1 -0
  7. package/dist/client/constants.d.ts +1 -0
  8. package/dist/client/e7b9d67c6a964bec.js +10 -0
  9. package/dist/client/index.js +1 -566
  10. package/dist/client/triggers/collection.d.ts +14 -0
  11. package/dist/client/triggers/index.d.ts +3 -3
  12. package/dist/client/triggers/schedule/ScheduleModes.d.ts +170 -0
  13. package/dist/client/triggers/schedule/TriggerScheduleConfig.d.ts +10 -0
  14. package/dist/client/triggers/schedule/index.d.ts +13 -0
  15. package/dist/client/variable.d.ts +16 -1
  16. package/dist/externalVersion.js +11 -11
  17. package/dist/locale/zh-CN.json +19 -5
  18. package/dist/node_modules/cron-parser/package.json +1 -1
  19. package/dist/node_modules/lru-cache/package.json +1 -1
  20. package/dist/server/Plugin.d.ts +13 -6
  21. package/dist/server/Plugin.js +165 -83
  22. package/dist/server/Processor.js +3 -3
  23. package/dist/server/actions/workflows.d.ts +5 -0
  24. package/dist/server/actions/workflows.js +59 -61
  25. package/dist/server/collections/executions.js +8 -0
  26. package/dist/server/collections/workflows.js +2 -2
  27. package/dist/server/index.d.ts +1 -1
  28. package/dist/server/index.js +2 -0
  29. package/dist/server/instructions/CreateInstruction.js +1 -1
  30. package/dist/server/instructions/DestroyInstruction.js +1 -1
  31. package/dist/server/instructions/UpdateInstruction.js +1 -1
  32. package/dist/server/repositories/WorkflowRepository.d.ts +12 -0
  33. package/dist/server/repositories/WorkflowRepository.js +112 -0
  34. package/dist/server/triggers/CollectionTrigger.d.ts +7 -2
  35. package/dist/server/triggers/CollectionTrigger.js +104 -73
  36. package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.d.ts +3 -2
  37. package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.js +51 -17
  38. package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.d.ts +1 -0
  39. package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.js +3 -0
  40. package/dist/server/triggers/ScheduleTrigger/index.d.ts +1 -0
  41. package/dist/server/triggers/ScheduleTrigger/index.js +7 -0
  42. package/dist/server/triggers/index.d.ts +4 -2
  43. package/dist/server/triggers/index.js +4 -0
  44. package/package.json +3 -3
@@ -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");
@@ -58,6 +59,7 @@ var import_CreateInstruction = __toESM(require("./instructions/CreateInstruction
58
59
  var import_DestroyInstruction = __toESM(require("./instructions/DestroyInstruction"));
59
60
  var import_QueryInstruction = __toESM(require("./instructions/QueryInstruction"));
60
61
  var import_UpdateInstruction = __toESM(require("./instructions/UpdateInstruction"));
62
+ var import_WorkflowRepository = __toESM(require("./repositories/WorkflowRepository"));
61
63
  class PluginWorkflowServer extends import_server.Plugin {
62
64
  instructions = new import_utils.Registry();
63
65
  triggers = new import_utils.Registry();
@@ -71,23 +73,10 @@ class PluginWorkflowServer extends import_server.Plugin {
71
73
  loggerCache;
72
74
  meter = null;
73
75
  checker = null;
74
- onBeforeSave = async (instance, options) => {
76
+ onBeforeSave = async (instance, { transaction }) => {
75
77
  const Model = instance.constructor;
76
78
  if (instance.enabled) {
77
79
  instance.set("current", true);
78
- } else if (!instance.current) {
79
- const count = await Model.count({
80
- where: {
81
- key: instance.key
82
- },
83
- transaction: options.transaction
84
- });
85
- if (!count) {
86
- instance.set("current", true);
87
- }
88
- }
89
- if (!instance.changed("enabled") || !instance.enabled) {
90
- return;
91
80
  }
92
81
  const previous = await Model.findOne({
93
82
  where: {
@@ -97,39 +86,40 @@ class PluginWorkflowServer extends import_server.Plugin {
97
86
  [import_database.Op.ne]: instance.id
98
87
  }
99
88
  },
100
- transaction: options.transaction
89
+ transaction
101
90
  });
102
- if (previous) {
91
+ if (!previous) {
92
+ instance.set("current", true);
93
+ }
94
+ if (instance.current && previous) {
103
95
  await previous.update(
104
96
  { enabled: false, current: null },
105
97
  {
106
- transaction: options.transaction,
98
+ transaction,
107
99
  hooks: false
108
100
  }
109
101
  );
110
- this.toggle(previous, false);
102
+ this.toggle(previous, false, { transaction });
111
103
  }
112
104
  };
113
- async onSync(message) {
105
+ async handleSyncMessage(message) {
114
106
  if (message.type === "statusChange") {
115
- const workflowId = Number.parseInt(message.workflowId, 10);
116
- const enabled = Number.parseInt(message.enabled, 10);
117
- if (enabled) {
118
- let workflow = this.enabledCache.get(workflowId);
107
+ if (message.enabled) {
108
+ let workflow = this.enabledCache.get(message.workflowId);
119
109
  if (workflow) {
120
110
  await workflow.reload();
121
111
  } else {
122
112
  workflow = await this.db.getRepository("workflows").findOne({
123
- filterByTk: workflowId
113
+ filterByTk: message.workflowId
124
114
  });
125
115
  }
126
116
  if (workflow) {
127
- this.toggle(workflow, true, true);
117
+ this.toggle(workflow, true, { silent: true });
128
118
  }
129
119
  } else {
130
- const workflow = this.enabledCache.get(workflowId);
120
+ const workflow = this.enabledCache.get(message.workflowId);
131
121
  if (workflow) {
132
- this.toggle(workflow, false, true);
122
+ this.toggle(workflow, false, { silent: true });
133
123
  }
134
124
  }
135
125
  }
@@ -137,7 +127,7 @@ class PluginWorkflowServer extends import_server.Plugin {
137
127
  /**
138
128
  * @experimental
139
129
  */
140
- getLogger(workflowId) {
130
+ getLogger(workflowId = "dispatcher") {
141
131
  const now = /* @__PURE__ */ new Date();
142
132
  const date = `${now.getFullYear()}-${`0${now.getMonth() + 1}`.slice(-2)}-${`0${now.getDate()}`.slice(-2)}`;
143
133
  const key = `${date}-${workflowId}}`;
@@ -200,6 +190,11 @@ class PluginWorkflowServer extends import_server.Plugin {
200
190
  this.registerInstruction(name, instruction);
201
191
  }
202
192
  }
193
+ async beforeLoad() {
194
+ this.db.registerRepositories({
195
+ WorkflowRepository: import_WorkflowRepository.default
196
+ });
197
+ }
203
198
  /**
204
199
  * @internal
205
200
  */
@@ -248,31 +243,42 @@ class PluginWorkflowServer extends import_server.Plugin {
248
243
  }
249
244
  });
250
245
  db.on("workflows.beforeSave", this.onBeforeSave);
251
- db.on("workflows.afterCreate", (model) => {
246
+ db.on("workflows.afterCreate", (model, { transaction }) => {
252
247
  if (model.enabled) {
253
- this.toggle(model);
248
+ this.toggle(model, true, { transaction });
254
249
  }
255
250
  });
256
- db.on("workflows.afterUpdate", (model) => this.toggle(model));
257
- db.on("workflows.beforeDestroy", (model) => this.toggle(model, false));
251
+ db.on(
252
+ "workflows.afterUpdate",
253
+ (model, { transaction }) => this.toggle(model, model.enabled, { transaction })
254
+ );
255
+ db.on(
256
+ "workflows.afterDestroy",
257
+ (model, { transaction }) => this.toggle(model, false, { transaction })
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({
263
263
  filter: { enabled: true }
264
264
  });
265
265
  workflows.forEach((workflow) => {
266
- this.toggle(workflow);
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 () => {
274
280
  for (const workflow of this.enabledCache.values()) {
275
- this.toggle(workflow, false);
281
+ this.toggle(workflow, false, { silent: true });
276
282
  }
277
283
  this.ready = false;
278
284
  if (this.events.length) {
@@ -286,7 +292,7 @@ class PluginWorkflowServer extends import_server.Plugin {
286
292
  }
287
293
  });
288
294
  }
289
- toggle(workflow, enable, silent = false) {
295
+ toggle(workflow, enable, { silent, transaction } = {}) {
290
296
  const type = workflow.get("type");
291
297
  const trigger = this.triggers.get(type);
292
298
  if (!trigger) {
@@ -306,11 +312,14 @@ class PluginWorkflowServer extends import_server.Plugin {
306
312
  this.enabledCache.delete(workflow.id);
307
313
  }
308
314
  if (!silent) {
309
- this.sync({
310
- type: "statusChange",
311
- workflowId: `${workflow.id}`,
312
- enabled: `${Number(next)}`
313
- });
315
+ this.sendSyncMessage(
316
+ {
317
+ type: "statusChange",
318
+ workflowId: workflow.id,
319
+ enabled: next
320
+ },
321
+ { transaction }
322
+ );
314
323
  }
315
324
  }
316
325
  trigger(workflow, context, options = {}) {
@@ -320,11 +329,24 @@ class PluginWorkflowServer extends import_server.Plugin {
320
329
  logger.debug(`ignored event data:`, context);
321
330
  return;
322
331
  }
332
+ if (!options.force && !options.manually && !workflow.enabled) {
333
+ logger.warn(`workflow ${workflow.id} is not enabled, event will be ignored`);
334
+ return;
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
+ }
323
345
  if (context == null) {
324
346
  logger.warn(`workflow ${workflow.id} event data context is null, event will be ignored`);
325
347
  return;
326
348
  }
327
- if (this.isWorkflowSync(workflow)) {
349
+ if (options.manually || this.isWorkflowSync(workflow)) {
328
350
  return this.triggerSync(workflow, context, options);
329
351
  }
330
352
  const { transaction, ...rest } = options;
@@ -333,6 +355,7 @@ class PluginWorkflowServer extends import_server.Plugin {
333
355
  logger.info(`new event triggered, now events: ${this.events.length}`);
334
356
  logger.debug(`event data:`, { context });
335
357
  if (this.events.length > 1) {
358
+ logger.info(`new event is pending to be prepared after previous preparation is finished`);
336
359
  return;
337
360
  }
338
361
  setTimeout(this.prepare);
@@ -360,31 +383,61 @@ class PluginWorkflowServer extends import_server.Plugin {
360
383
  `execution (${job.execution.id}) resuming from job (${job.id}) added to pending list`
361
384
  );
362
385
  this.pending.push([job.execution, job]);
386
+ if (this.executing) {
387
+ await this.executing;
388
+ }
363
389
  this.dispatch();
364
390
  }
365
391
  /**
366
392
  * Start a deferred execution
367
393
  * @experimental
368
394
  */
369
- start(execution) {
395
+ async start(execution) {
370
396
  if (execution.status !== import_constants.EXECUTION_STATUS.STARTED) {
371
397
  return;
372
398
  }
373
399
  this.pending.push([execution]);
400
+ if (this.executing) {
401
+ await this.executing;
402
+ }
374
403
  this.dispatch();
375
404
  }
376
- createProcessor(execution, options = {}) {
377
- return new import_Processor.default(execution, { ...options, plugin: this });
405
+ async validateEvent(workflow, context, options) {
406
+ const trigger = this.triggers.get(workflow.type);
407
+ const triggerValid = await trigger.validateEvent(workflow, context, options);
408
+ if (!triggerValid) {
409
+ return false;
410
+ }
411
+ const { stack } = options;
412
+ let valid = true;
413
+ if ((stack == null ? void 0 : stack.length) > 0) {
414
+ const existed = await workflow.countExecutions({
415
+ where: {
416
+ id: stack
417
+ },
418
+ transaction: options.transaction
419
+ });
420
+ if (existed) {
421
+ this.getLogger(workflow.id).warn(
422
+ `workflow ${workflow.id} has already been triggered in stacks executions (${stack}), and newly triggering will be skipped.`
423
+ );
424
+ valid = false;
425
+ }
426
+ }
427
+ return valid;
378
428
  }
379
429
  async createExecution(workflow, context, options) {
380
- const { transaction = await this.db.sequelize.transaction(), deferred } = options;
381
- const trigger = this.triggers.get(workflow.type);
382
- const valid = await trigger.validateEvent(workflow, context, { ...options, transaction });
430
+ var _a;
431
+ const { deferred } = options;
432
+ const transaction = await this.useDataSourceTransaction("main", options.transaction, true);
433
+ const sameTransaction = options.transaction === transaction;
434
+ const valid = await this.validateEvent(workflow, context, { ...options, transaction });
383
435
  if (!valid) {
384
- if (!options.transaction) {
436
+ if (!sameTransaction) {
385
437
  await transaction.commit();
386
438
  }
387
- return null;
439
+ (_a = options.onTriggerFail) == null ? void 0 : _a.call(options, workflow, context, options);
440
+ return Promise.reject(new Error("event is not valid"));
388
441
  }
389
442
  let execution;
390
443
  try {
@@ -393,12 +446,13 @@ class PluginWorkflowServer extends import_server.Plugin {
393
446
  context,
394
447
  key: workflow.key,
395
448
  eventKey: options.eventKey ?? (0, import_crypto.randomUUID)(),
449
+ stack: options.stack,
396
450
  status: deferred ? import_constants.EXECUTION_STATUS.STARTED : import_constants.EXECUTION_STATUS.QUEUEING
397
451
  },
398
452
  { transaction }
399
453
  );
400
454
  } catch (err) {
401
- if (!options.transaction) {
455
+ if (!sameTransaction) {
402
456
  await transaction.rollback();
403
457
  }
404
458
  throw err;
@@ -419,7 +473,7 @@ class PluginWorkflowServer extends import_server.Plugin {
419
473
  transaction
420
474
  }
421
475
  );
422
- if (!options.transaction) {
476
+ if (!sameTransaction) {
423
477
  await transaction.commit();
424
478
  }
425
479
  execution.workflow = workflow;
@@ -432,7 +486,7 @@ class PluginWorkflowServer extends import_server.Plugin {
432
486
  const event = this.events.shift();
433
487
  this.eventsCount = this.events.length;
434
488
  if (!event) {
435
- this.getLogger("dispatcher").warn(`events queue is empty, no need to prepare`);
489
+ this.getLogger("dispatcher").info(`events queue is empty, no need to prepare`);
436
490
  return;
437
491
  }
438
492
  const logger = this.getLogger(event[0].id);
@@ -442,8 +496,8 @@ class PluginWorkflowServer extends import_server.Plugin {
442
496
  if ((execution == null ? void 0 : execution.status) === import_constants.EXECUTION_STATUS.QUEUEING && !this.executing && !this.pending.length) {
443
497
  this.pending.push([execution]);
444
498
  }
445
- } catch (err) {
446
- logger.error(`failed to create execution: ${err.message}`, err);
499
+ } catch (error) {
500
+ logger.error(`failed to create execution:`, { error });
447
501
  }
448
502
  if (this.events.length) {
449
503
  await this.prepare();
@@ -465,38 +519,56 @@ class PluginWorkflowServer extends import_server.Plugin {
465
519
  }
466
520
  this.executing = (async () => {
467
521
  let next = null;
468
- try {
469
- if (this.pending.length) {
470
- next = this.pending.shift();
471
- this.getLogger(next[0].workflowId).info(`pending execution (${next[0].id}) ready to process`);
472
- } else {
473
- const execution = await this.db.getRepository("executions").findOne({
474
- filter: {
475
- status: import_constants.EXECUTION_STATUS.QUEUEING,
476
- "workflow.enabled": true,
477
- "workflow.id": {
478
- [import_database.Op.not]: null
479
- }
522
+ if (this.pending.length) {
523
+ next = this.pending.shift();
524
+ this.getLogger(next[0].workflowId).info(`pending execution (${next[0].id}) ready to process`);
525
+ } else {
526
+ try {
527
+ await this.db.sequelize.transaction(
528
+ {
529
+ isolationLevel: this.db.options.dialect === "sqlite" ? [][0] : import_sequelize.Transaction.ISOLATION_LEVELS.REPEATABLE_READ
480
530
  },
481
- appends: ["workflow"],
482
- sort: "id"
483
- });
484
- if (execution) {
485
- this.getLogger(execution.workflowId).info(`execution (${execution.id}) fetched from db`);
486
- next = [execution];
487
- }
488
- }
489
- if (next) {
490
- await this.process(...next);
491
- }
492
- } finally {
493
- this.executing = null;
494
- if (next) {
495
- this.dispatch();
531
+ async (transaction) => {
532
+ const execution = await this.db.getRepository("executions").findOne({
533
+ filter: {
534
+ status: import_constants.EXECUTION_STATUS.QUEUEING,
535
+ "workflow.enabled": true
536
+ },
537
+ sort: "id",
538
+ transaction
539
+ });
540
+ if (execution) {
541
+ this.getLogger(execution.workflowId).info(`execution (${execution.id}) fetched from db`);
542
+ await execution.update(
543
+ {
544
+ status: import_constants.EXECUTION_STATUS.STARTED
545
+ },
546
+ { transaction }
547
+ );
548
+ execution.workflow = this.enabledCache.get(execution.workflowId);
549
+ next = [execution];
550
+ } else {
551
+ this.getLogger("dispatcher").info(`no execution in db queued to process`);
552
+ }
553
+ }
554
+ );
555
+ } catch (error) {
556
+ this.getLogger("dispatcher").error(`fetching execution from db failed: ${error.message}`, { error });
496
557
  }
497
558
  }
559
+ if (next) {
560
+ await this.process(...next);
561
+ }
562
+ this.executing = null;
563
+ if (next) {
564
+ this.getLogger("dispatcher").info(`last process finished, will do another dispatch`);
565
+ this.dispatch();
566
+ }
498
567
  })();
499
568
  }
569
+ createProcessor(execution, options = {}) {
570
+ return new import_Processor.default(execution, { ...options, plugin: this });
571
+ }
500
572
  async process(execution, job, options = {}) {
501
573
  var _a, _b;
502
574
  if (execution.status === import_constants.EXECUTION_STATUS.QUEUEING) {
@@ -510,13 +582,23 @@ class PluginWorkflowServer extends import_server.Plugin {
510
582
  await (job ? processor.resume(job) : processor.start());
511
583
  logger.info(`execution (${execution.id}) finished with status: ${execution.status}`, { execution });
512
584
  if (execution.status && ((_b = (_a = execution.workflow.options) == null ? void 0 : _a.deleteExecutionOnStatus) == null ? void 0 : _b.includes(execution.status))) {
513
- await execution.destroy();
585
+ await execution.destroy({ transaction: processor.mainTransaction });
514
586
  }
515
587
  } catch (err) {
516
588
  logger.error(`execution (${execution.id}) error: ${err.message}`, err);
517
589
  }
518
590
  return processor;
519
591
  }
592
+ async execute(workflow, values, options = {}) {
593
+ const trigger = this.triggers.get(workflow.type);
594
+ if (!trigger) {
595
+ throw new Error(`trigger type "${workflow.type}" of workflow ${workflow.id} is not registered`);
596
+ }
597
+ if (!trigger.execute) {
598
+ throw new Error(`"execute" method of trigger ${workflow.type} is not implemented`);
599
+ }
600
+ return trigger.execute(workflow, values, options);
601
+ }
520
602
  /**
521
603
  * @experimental
522
604
  * @param {string} dataSourceName
@@ -117,11 +117,11 @@ class Processor {
117
117
  execution,
118
118
  options: { plugin }
119
119
  } = this;
120
- if (!execution.workflow) {
121
- execution.workflow = plugin.enabledCache.get(execution.workflowId);
122
- }
123
120
  this.mainTransaction = plugin.useDataSourceTransaction("main", this.transaction);
124
121
  const transaction = this.mainTransaction;
122
+ if (!execution.workflow) {
123
+ execution.workflow = plugin.enabledCache.get(execution.workflowId) || await execution.getWorkflow({ transaction });
124
+ }
125
125
  const nodes = await execution.workflow.getNodes({ transaction });
126
126
  this.makeNodes(nodes);
127
127
  const jobs = await execution.getJobs({
@@ -11,4 +11,9 @@ export declare function update(context: Context, next: any): Promise<void>;
11
11
  export declare function destroy(context: Context, next: any): Promise<void>;
12
12
  export declare function revision(context: Context, next: any): Promise<void>;
13
13
  export declare function sync(context: Context, next: any): Promise<void>;
14
+ /**
15
+ * @deprecated
16
+ * Keep for action trigger compatibility
17
+ */
14
18
  export declare function trigger(context: Context, next: any): Promise<any>;
19
+ export declare function execute(context: Context, next: any): Promise<any>;
@@ -37,6 +37,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
37
37
  var workflows_exports = {};
38
38
  __export(workflows_exports, {
39
39
  destroy: () => destroy,
40
+ execute: () => execute,
40
41
  revision: () => revision,
41
42
  sync: () => sync,
42
43
  trigger: () => trigger,
@@ -90,69 +91,13 @@ async function destroy(context, next) {
90
91
  next();
91
92
  }
92
93
  async function revision(context, next) {
93
- const plugin = context.app.getPlugin(import_Plugin.default);
94
94
  const repository = import_actions.utils.getRepositoryFromParams(context);
95
95
  const { filterByTk, filter = {}, values = {} } = context.action.params;
96
- context.body = await context.db.sequelize.transaction(async (transaction) => {
97
- const origin = await repository.findOne({
98
- filterByTk,
99
- filter,
100
- appends: ["nodes"],
101
- context,
102
- transaction
103
- });
104
- const trigger2 = plugin.triggers.get(origin.type);
105
- const revisionData = filter.key ? {
106
- key: filter.key,
107
- title: origin.title,
108
- triggerTitle: origin.triggerTitle,
109
- allExecuted: origin.allExecuted
110
- } : values;
111
- const instance = await repository.create({
112
- values: {
113
- title: `${origin.title} copy`,
114
- description: origin.description,
115
- ...revisionData,
116
- sync: origin.sync,
117
- type: origin.type,
118
- config: typeof trigger2.duplicateConfig === "function" ? await trigger2.duplicateConfig(origin, { transaction }) : origin.config
119
- },
120
- transaction
121
- });
122
- const originalNodesMap = /* @__PURE__ */ new Map();
123
- origin.nodes.forEach((node) => {
124
- originalNodesMap.set(node.id, node);
125
- });
126
- const oldToNew = /* @__PURE__ */ new Map();
127
- const newToOld = /* @__PURE__ */ new Map();
128
- for await (const node of origin.nodes) {
129
- const instruction = plugin.instructions.get(node.type);
130
- const newNode = await instance.createNode(
131
- {
132
- type: node.type,
133
- key: node.key,
134
- config: typeof instruction.duplicateConfig === "function" ? await instruction.duplicateConfig(node, { transaction }) : node.config,
135
- title: node.title,
136
- branchIndex: node.branchIndex
137
- },
138
- { transaction }
139
- );
140
- oldToNew.set(node.id, newNode);
141
- newToOld.set(newNode.id, node);
142
- }
143
- for await (const [oldId, newNode] of oldToNew.entries()) {
144
- const oldNode = originalNodesMap.get(oldId);
145
- const newUpstream = oldNode.upstreamId ? oldToNew.get(oldNode.upstreamId) : null;
146
- const newDownstream = oldNode.downstreamId ? oldToNew.get(oldNode.downstreamId) : null;
147
- await newNode.update(
148
- {
149
- upstreamId: (newUpstream == null ? void 0 : newUpstream.id) ?? null,
150
- downstreamId: (newDownstream == null ? void 0 : newDownstream.id) ?? null
151
- },
152
- { transaction }
153
- );
154
- }
155
- return instance;
96
+ context.body = await repository.revision({
97
+ filterByTk,
98
+ filter,
99
+ values,
100
+ context
156
101
  });
157
102
  await next();
158
103
  }
@@ -174,9 +119,62 @@ async function sync(context, next) {
174
119
  async function trigger(context, next) {
175
120
  return next();
176
121
  }
122
+ async function execute(context, next) {
123
+ const plugin = context.app.pm.get(import_Plugin.default);
124
+ const { filterByTk, values, autoRevision } = context.action.params;
125
+ if (!values) {
126
+ return context.throw(400, "values is required");
127
+ }
128
+ if (!filterByTk) {
129
+ return context.throw(400, "filterByTk is required");
130
+ }
131
+ const id = Number.parseInt(filterByTk, 10);
132
+ if (Number.isNaN(id)) {
133
+ return context.throw(400, "filterByTk is invalid");
134
+ }
135
+ const repository = import_actions.utils.getRepositoryFromParams(context);
136
+ const workflow = plugin.enabledCache.get(id) || await repository.findOne({ filterByTk });
137
+ if (!workflow) {
138
+ return context.throw(404, "workflow not found");
139
+ }
140
+ const { executed } = workflow;
141
+ let processor;
142
+ try {
143
+ processor = await plugin.execute(workflow, values, { manually: true });
144
+ if (!processor) {
145
+ return context.throw(400, "workflow not triggered");
146
+ }
147
+ } catch (ex) {
148
+ return context.throw(400, ex.message);
149
+ }
150
+ context.action.mergeParams({
151
+ filter: { key: workflow.key }
152
+ });
153
+ let newVersion;
154
+ if (!executed && autoRevision) {
155
+ newVersion = await repository.revision({
156
+ filterByTk: workflow.id,
157
+ filter: { key: workflow.key },
158
+ values: {
159
+ current: workflow.current,
160
+ enabled: workflow.enabled
161
+ },
162
+ context
163
+ });
164
+ }
165
+ context.body = {
166
+ execution: {
167
+ id: processor.execution.id,
168
+ status: processor.execution.status
169
+ },
170
+ newVersionId: newVersion == null ? void 0 : newVersion.id
171
+ };
172
+ return next();
173
+ }
177
174
  // Annotate the CommonJS export names for ESM import in node:
178
175
  0 && (module.exports = {
179
176
  destroy,
177
+ execute,
180
178
  revision,
181
179
  sync,
182
180
  trigger,
@@ -61,6 +61,14 @@ var executions_default = {
61
61
  {
62
62
  type: "integer",
63
63
  name: "status"
64
+ },
65
+ {
66
+ type: "json",
67
+ name: "stack"
68
+ },
69
+ {
70
+ type: "json",
71
+ name: "output"
64
72
  }
65
73
  ]
66
74
  };
@@ -34,6 +34,7 @@ function workflows_default() {
34
34
  dumpRules: "required",
35
35
  name: "workflows",
36
36
  shared: true,
37
+ repository: "WorkflowRepository",
37
38
  fields: [
38
39
  {
39
40
  name: "key",
@@ -90,8 +91,7 @@ function workflows_default() {
90
91
  },
91
92
  {
92
93
  type: "boolean",
93
- name: "current",
94
- defaultValue: false
94
+ name: "current"
95
95
  },
96
96
  {
97
97
  type: "boolean",
@@ -13,5 +13,5 @@ export * from './functions';
13
13
  export * from './logicCalculate';
14
14
  export { Trigger } from './triggers';
15
15
  export { default as Processor } from './Processor';
16
- export { default } from './Plugin';
16
+ export { default, EventOptions } from './Plugin';
17
17
  export * from './types';
@@ -37,6 +37,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
37
37
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
38
  var server_exports = {};
39
39
  __export(server_exports, {
40
+ EventOptions: () => import_Plugin.EventOptions,
40
41
  Processor: () => import_Processor.default,
41
42
  Trigger: () => import_triggers.Trigger,
42
43
  default: () => import_Plugin.default
@@ -53,6 +54,7 @@ var import_Plugin = __toESM(require("./Plugin"));
53
54
  __reExport(server_exports, require("./types"), module.exports);
54
55
  // Annotate the CommonJS export names for ESM import in node:
55
56
  0 && (module.exports = {
57
+ EventOptions,
56
58
  Processor,
57
59
  Trigger,
58
60
  ...require("./utils"),