@nocobase/plugin-workflow 1.7.0-alpha.1 → 1.7.0-alpha.11

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 (75) hide show
  1. package/dist/client/3d24e559cfbba5d8.js +10 -0
  2. package/dist/client/90a4f6d29bd453a7.js +10 -0
  3. package/dist/client/WorkflowTasks.d.ts +11 -11
  4. package/dist/client/a2fc280565d1c746.js +10 -0
  5. package/dist/client/f4370978c40502d7.js +10 -0
  6. package/dist/client/index.d.ts +1 -0
  7. package/dist/client/index.js +1 -1
  8. package/dist/client/locale/index.d.ts +2 -1
  9. package/dist/client/schemas/executions.d.ts +126 -125
  10. package/dist/client/triggers/schedule/RepeatField.d.ts +2 -1
  11. package/dist/common/collections/executions.d.ts +136 -0
  12. package/dist/common/collections/executions.js +125 -0
  13. package/dist/common/collections/flow_nodes.d.ts +44 -0
  14. package/dist/common/collections/flow_nodes.js +88 -0
  15. package/dist/common/collections/jobs.d.ts +37 -0
  16. package/dist/common/collections/jobs.js +74 -0
  17. package/dist/common/collections/workflowStats.d.ts +37 -0
  18. package/dist/common/collections/workflowStats.js +59 -0
  19. package/dist/common/collections/workflowTasks.d.ts +10 -0
  20. package/dist/common/collections/workflowTasks.js +64 -0
  21. package/dist/common/collections/workflowVersionStats.d.ts +37 -0
  22. package/dist/common/collections/workflowVersionStats.js +59 -0
  23. package/dist/common/collections/workflows.d.ts +250 -0
  24. package/dist/common/collections/workflows.js +225 -0
  25. package/dist/common/constants.d.ts +9 -0
  26. package/dist/common/constants.js +36 -0
  27. package/dist/externalVersion.js +13 -13
  28. package/dist/locale/de-DE.json +216 -0
  29. package/dist/locale/it-IT.json +123 -18
  30. package/dist/locale/nl-NL.json +100 -0
  31. package/dist/locale/zh-CN.json +4 -0
  32. package/dist/node_modules/cron-parser/package.json +1 -1
  33. package/dist/node_modules/lru-cache/package.json +1 -1
  34. package/dist/node_modules/nodejs-snowflake/LICENSE +201 -0
  35. package/dist/node_modules/nodejs-snowflake/nodejs_snowflake.d.ts +62 -0
  36. package/dist/node_modules/nodejs-snowflake/nodejs_snowflake.js +1 -0
  37. package/dist/node_modules/nodejs-snowflake/nodejs_snowflake_bg.wasm +0 -0
  38. package/dist/node_modules/nodejs-snowflake/package.json +1 -0
  39. package/dist/server/Dispatcher.d.ts +11 -0
  40. package/dist/server/Dispatcher.js +35 -0
  41. package/dist/server/Plugin.d.ts +8 -1
  42. package/dist/server/Plugin.js +118 -70
  43. package/dist/server/Processor.d.ts +4 -11
  44. package/dist/server/Processor.js +48 -45
  45. package/dist/server/actions/nodes.js +7 -5
  46. package/dist/server/actions/workflowTasks.js +4 -2
  47. package/dist/server/actions/workflows.js +5 -2
  48. package/dist/server/collections/executions.js +12 -44
  49. package/dist/server/collections/flow_nodes.js +12 -57
  50. package/dist/server/collections/jobs.js +12 -36
  51. package/dist/server/collections/workflowStats.d.ts +11 -0
  52. package/dist/server/collections/workflowStats.js +43 -0
  53. package/dist/server/collections/workflowTasks.d.ts +2 -1
  54. package/dist/server/collections/workflowTasks.js +12 -33
  55. package/dist/server/collections/workflowVersionStats.d.ts +11 -0
  56. package/dist/server/collections/workflowVersionStats.js +43 -0
  57. package/dist/server/collections/workflows.d.ts +2 -1
  58. package/dist/server/collections/workflows.js +12 -101
  59. package/dist/server/migrations/20250320223415-stats.d.ts +14 -0
  60. package/dist/server/migrations/20250320223415-stats.js +82 -0
  61. package/dist/server/migrations/20250409164913-remove-jobs-auto-increment.d.ts +14 -0
  62. package/dist/server/migrations/20250409164913-remove-jobs-auto-increment.js +57 -0
  63. package/dist/server/repositories/WorkflowRepository.js +1 -2
  64. package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.d.ts +5 -3
  65. package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.js +39 -36
  66. package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.d.ts +4 -2
  67. package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.js +26 -24
  68. package/dist/server/types/Workflow.d.ts +0 -2
  69. package/dist/swagger/index.d.ts +0 -14
  70. package/dist/swagger/index.js +0 -14
  71. package/package.json +4 -3
  72. package/dist/client/4d75ef32f02d7285.js +0 -10
  73. package/dist/client/56ce448358002e64.js +0 -10
  74. package/dist/client/58bb427e05b600de.js +0 -10
  75. package/dist/client/739d458621edf81f.js +0 -10
@@ -0,0 +1,35 @@
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 Dispatcher_exports = {};
28
+ __export(Dispatcher_exports, {
29
+ default: () => Dispatcher
30
+ });
31
+ module.exports = __toCommonJS(Dispatcher_exports);
32
+ class Dispatcher {
33
+ constructor() {
34
+ }
35
+ }
@@ -6,6 +6,7 @@
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 { Snowflake } from 'nodejs-snowflake';
9
10
  import { Transactionable } from 'sequelize';
10
11
  import { Plugin } from '@nocobase/server';
11
12
  import { Registry } from '@nocobase/utils';
@@ -31,6 +32,7 @@ export default class PluginWorkflowServer extends Plugin {
31
32
  triggers: Registry<Trigger>;
32
33
  functions: Registry<CustomFunction>;
33
34
  enabledCache: Map<number, WorkflowModel>;
35
+ snowflake: Snowflake;
34
36
  private ready;
35
37
  private executing;
36
38
  private pending;
@@ -40,6 +42,11 @@ export default class PluginWorkflowServer extends Plugin {
40
42
  private meter;
41
43
  private checker;
42
44
  private onBeforeSave;
45
+ private onAfterCreate;
46
+ private onAfterUpdate;
47
+ private onAfterDestroy;
48
+ private onAfterStart;
49
+ private onBeforeStop;
43
50
  handleSyncMessage(message: any): Promise<void>;
44
51
  /**
45
52
  * @experimental
@@ -91,6 +98,6 @@ export default class PluginWorkflowServer extends Plugin {
91
98
  /**
92
99
  * @experimental
93
100
  */
94
- toggleTaskStatus(task: WorkflowTaskModel, done: boolean, { transaction }: Transactionable): Promise<void>;
101
+ toggleTaskStatus(task: WorkflowTaskModel, on: boolean, { transaction }: Transactionable): Promise<void>;
95
102
  }
96
103
  export {};
@@ -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_nodejs_snowflake = require("nodejs-snowflake");
44
45
  var import_sequelize = require("sequelize");
45
46
  var import_lru_cache = __toESM(require("lru-cache"));
46
47
  var import_database = require("@nocobase/database");
@@ -66,6 +67,7 @@ class PluginWorkflowServer extends import_server.Plugin {
66
67
  triggers = new import_utils.Registry();
67
68
  functions = new import_utils.Registry();
68
69
  enabledCache = /* @__PURE__ */ new Map();
70
+ snowflake;
69
71
  ready = false;
70
72
  executing = null;
71
73
  pending = [];
@@ -76,6 +78,9 @@ class PluginWorkflowServer extends import_server.Plugin {
76
78
  checker = null;
77
79
  onBeforeSave = async (instance, { transaction }) => {
78
80
  const Model = instance.constructor;
81
+ if (!instance.key) {
82
+ instance.set("key", (0, import_utils.uid)());
83
+ }
79
84
  if (instance.enabled) {
80
85
  instance.set("current", true);
81
86
  }
@@ -103,6 +108,82 @@ class PluginWorkflowServer extends import_server.Plugin {
103
108
  this.toggle(previous, false, { transaction });
104
109
  }
105
110
  };
111
+ onAfterCreate = async (model, { transaction }) => {
112
+ const WorkflowStatsModel = this.db.getModel("workflowStats");
113
+ let stats = await WorkflowStatsModel.findOne({
114
+ where: { key: model.key },
115
+ transaction
116
+ });
117
+ if (!stats) {
118
+ stats = await model.createStats({ executed: 0 }, { transaction });
119
+ }
120
+ model.stats = stats;
121
+ model.versionStats = await model.createVersionStats({ id: model.id }, { transaction });
122
+ if (model.enabled) {
123
+ this.toggle(model, true, { transaction });
124
+ }
125
+ };
126
+ onAfterUpdate = async (model, { transaction }) => {
127
+ model.stats = await model.getStats({ transaction });
128
+ model.versionStats = await model.getVersionStats({ transaction });
129
+ this.toggle(model, model.enabled, { transaction });
130
+ };
131
+ onAfterDestroy = async (model, { transaction }) => {
132
+ this.toggle(model, false, { transaction });
133
+ const TaskRepo = this.db.getRepository("workflowTasks");
134
+ await TaskRepo.destroy({
135
+ filter: {
136
+ workflowId: model.id
137
+ },
138
+ transaction
139
+ });
140
+ };
141
+ // [Life Cycle]:
142
+ // * load all workflows in db
143
+ // * add all hooks for enabled workflows
144
+ // * add hooks for create/update[enabled]/delete workflow to add/remove specific hooks
145
+ onAfterStart = async () => {
146
+ this.ready = true;
147
+ const collection = this.db.getCollection("workflows");
148
+ const workflows = await collection.repository.find({
149
+ filter: { enabled: true },
150
+ appends: ["stats", "versionStats"]
151
+ });
152
+ for (const workflow of workflows) {
153
+ if (!workflow.stats) {
154
+ workflow.stats = await workflow.createStats({ executed: 0 });
155
+ }
156
+ if (!workflow.versionStats) {
157
+ workflow.versionStats = await workflow.createVersionStats({ executed: 0 });
158
+ }
159
+ this.toggle(workflow, true, { silent: true });
160
+ }
161
+ this.checker = setInterval(() => {
162
+ this.getLogger("dispatcher").info(`(cycling) check for queueing executions`);
163
+ this.dispatch();
164
+ }, 3e5);
165
+ this.app.on("workflow:dispatch", () => {
166
+ this.app.logger.info("workflow:dispatch");
167
+ this.dispatch();
168
+ });
169
+ this.getLogger("dispatcher").info("(starting) check for queueing executions");
170
+ this.dispatch();
171
+ };
172
+ onBeforeStop = async () => {
173
+ for (const workflow of this.enabledCache.values()) {
174
+ this.toggle(workflow, false, { silent: true });
175
+ }
176
+ this.ready = false;
177
+ if (this.events.length) {
178
+ await this.prepare();
179
+ }
180
+ if (this.executing) {
181
+ await this.executing;
182
+ }
183
+ if (this.checker) {
184
+ clearInterval(this.checker);
185
+ }
186
+ };
106
187
  async handleSyncMessage(message) {
107
188
  if (message.type === "statusChange") {
108
189
  if (message.enabled) {
@@ -196,6 +277,13 @@ class PluginWorkflowServer extends import_server.Plugin {
196
277
  WorkflowRepository: import_WorkflowRepository.default,
197
278
  WorkflowTasksRepository: import_WorkflowTasksRepository.default
198
279
  });
280
+ const PluginRepo = this.db.getRepository("applicationPlugins");
281
+ const pluginRecord = await PluginRepo.findOne({
282
+ filter: { name: this.name }
283
+ });
284
+ this.snowflake = new import_nodejs_snowflake.Snowflake({
285
+ custom_epoch: pluginRecord == null ? void 0 : pluginRecord.createdAt.getTime()
286
+ });
199
287
  }
200
288
  /**
201
289
  * @internal
@@ -247,54 +335,11 @@ class PluginWorkflowServer extends import_server.Plugin {
247
335
  }
248
336
  });
249
337
  db.on("workflows.beforeSave", this.onBeforeSave);
250
- db.on("workflows.afterCreate", (model, { transaction }) => {
251
- if (model.enabled) {
252
- this.toggle(model, true, { transaction });
253
- }
254
- });
255
- db.on(
256
- "workflows.afterUpdate",
257
- (model, { transaction }) => this.toggle(model, model.enabled, { transaction })
258
- );
259
- db.on(
260
- "workflows.afterDestroy",
261
- (model, { transaction }) => this.toggle(model, false, { transaction })
262
- );
263
- this.app.on("afterStart", async () => {
264
- this.ready = true;
265
- const collection = db.getCollection("workflows");
266
- const workflows = await collection.repository.find({
267
- filter: { enabled: true }
268
- });
269
- workflows.forEach((workflow) => {
270
- this.toggle(workflow, true, { silent: true });
271
- });
272
- this.checker = setInterval(() => {
273
- this.getLogger("dispatcher").info(`(cycling) check for queueing executions`);
274
- this.dispatch();
275
- }, 3e5);
276
- this.app.on("workflow:dispatch", () => {
277
- this.app.logger.info("workflow:dispatch");
278
- this.dispatch();
279
- });
280
- this.getLogger("dispatcher").info("(starting) check for queueing executions");
281
- this.dispatch();
282
- });
283
- this.app.on("beforeStop", async () => {
284
- for (const workflow of this.enabledCache.values()) {
285
- this.toggle(workflow, false, { silent: true });
286
- }
287
- this.ready = false;
288
- if (this.events.length) {
289
- await this.prepare();
290
- }
291
- if (this.executing) {
292
- await this.executing;
293
- }
294
- if (this.checker) {
295
- clearInterval(this.checker);
296
- }
297
- });
338
+ db.on("workflows.afterCreate", this.onAfterCreate);
339
+ db.on("workflows.afterUpdate", this.onAfterUpdate);
340
+ db.on("workflows.afterDestroy", this.onAfterDestroy);
341
+ this.app.on("afterStart", this.onAfterStart);
342
+ this.app.on("beforeStop", this.onBeforeStop);
298
343
  }
299
344
  toggle(workflow, enable, { silent, transaction } = {}) {
300
345
  const type = workflow.get("type");
@@ -308,11 +353,14 @@ class PluginWorkflowServer extends import_server.Plugin {
308
353
  const prev = workflow.previous();
309
354
  if (prev.config) {
310
355
  trigger.off({ ...workflow.get(), ...prev });
356
+ this.getLogger(workflow.id).info(`toggle OFF workflow ${workflow.id} based on configuration before updated`);
311
357
  }
312
358
  trigger.on(workflow);
359
+ this.getLogger(workflow.id).info(`toggle ON workflow ${workflow.id}`);
313
360
  this.enabledCache.set(workflow.id, workflow);
314
361
  } else {
315
362
  trigger.off(workflow);
363
+ this.getLogger(workflow.id).info(`toggle OFF workflow ${workflow.id}`);
316
364
  this.enabledCache.delete(workflow.id);
317
365
  }
318
366
  if (!silent) {
@@ -464,21 +512,20 @@ class PluginWorkflowServer extends import_server.Plugin {
464
512
  throw err;
465
513
  }
466
514
  this.getLogger(workflow.id).info(`execution of workflow ${workflow.id} created as ${execution.id}`);
467
- await workflow.increment(["executed", "allExecuted"], { transaction });
515
+ if (!workflow.stats) {
516
+ workflow.stats = await workflow.getStats({ transaction });
517
+ }
518
+ await workflow.stats.increment("executed", { transaction });
468
519
  if (this.db.options.dialect !== "postgres") {
469
- await workflow.reload({ transaction });
520
+ await workflow.stats.reload({ transaction });
521
+ }
522
+ if (!workflow.versionStats) {
523
+ workflow.versionStats = await workflow.getVersionStats({ transaction });
524
+ }
525
+ await workflow.versionStats.increment("executed", { transaction });
526
+ if (this.db.options.dialect !== "postgres") {
527
+ await workflow.versionStats.reload({ transaction });
470
528
  }
471
- await workflow.constructor.update(
472
- {
473
- allExecuted: workflow.allExecuted
474
- },
475
- {
476
- where: {
477
- key: workflow.key
478
- },
479
- transaction
480
- }
481
- );
482
529
  if (!sameTransaction) {
483
530
  await transaction.commit();
484
531
  }
@@ -632,10 +679,16 @@ class PluginWorkflowServer extends import_server.Plugin {
632
679
  /**
633
680
  * @experimental
634
681
  */
635
- async toggleTaskStatus(task, done, { transaction }) {
682
+ async toggleTaskStatus(task, on, { transaction }) {
636
683
  const { db } = this.app;
637
684
  const repository = db.getRepository("workflowTasks");
638
- if (done) {
685
+ if (on) {
686
+ await repository.updateOrCreate({
687
+ filterKeys: ["key", "type"],
688
+ values: task,
689
+ transaction
690
+ });
691
+ } else {
639
692
  await repository.destroy({
640
693
  filter: {
641
694
  type: task.type,
@@ -643,17 +696,12 @@ class PluginWorkflowServer extends import_server.Plugin {
643
696
  },
644
697
  transaction
645
698
  });
646
- } else {
647
- await repository.updateOrCreate({
648
- filterKeys: ["key", "type"],
649
- values: task,
650
- transaction
651
- });
652
699
  }
653
700
  if (task.userId) {
654
701
  const counts = await repository.countAll({
655
702
  where: {
656
- userId: task.userId
703
+ userId: task.userId,
704
+ workflowId: { [import_database.Op.ne]: null }
657
705
  },
658
706
  transaction
659
707
  }) || [];
@@ -44,16 +44,9 @@ export default class Processor {
44
44
  * @experimental
45
45
  */
46
46
  nodesMap: Map<number, FlowNodeModel>;
47
- /**
48
- * @experimental
49
- */
50
- jobsMap: Map<number, JobModel>;
51
- /**
52
- * @experimental
53
- */
54
- jobsMapByNodeKey: {
55
- [key: string]: any;
56
- };
47
+ private jobsMapByNodeKey;
48
+ private jobResultsMapByNodeKey;
49
+ private jobsToSave;
57
50
  /**
58
51
  * @experimental
59
52
  */
@@ -72,7 +65,7 @@ export default class Processor {
72
65
  /**
73
66
  * @experimental
74
67
  */
75
- saveJob(payload: JobModel | Record<string, any>): Promise<JobModel>;
68
+ saveJob(payload: JobModel | Record<string, any>): JobModel;
76
69
  /**
77
70
  * @experimental
78
71
  */
@@ -78,14 +78,9 @@ class Processor {
78
78
  * @experimental
79
79
  */
80
80
  nodesMap = /* @__PURE__ */ new Map();
81
- /**
82
- * @experimental
83
- */
84
- jobsMap = /* @__PURE__ */ new Map();
85
- /**
86
- * @experimental
87
- */
88
81
  jobsMapByNodeKey = {};
82
+ jobResultsMapByNodeKey = {};
83
+ jobsToSave = /* @__PURE__ */ new Map();
89
84
  /**
90
85
  * @experimental
91
86
  */
@@ -107,9 +102,9 @@ class Processor {
107
102
  }
108
103
  makeJobs(jobs) {
109
104
  jobs.forEach((job) => {
110
- this.jobsMap.set(job.id, job);
111
105
  const node = this.nodesMap.get(job.nodeId);
112
- this.jobsMapByNodeKey[node.key] = job.result;
106
+ this.jobsMapByNodeKey[node.key] = job;
107
+ this.jobResultsMapByNodeKey[node.key] = job.result;
113
108
  });
114
109
  }
115
110
  async prepare() {
@@ -179,11 +174,10 @@ class Processor {
179
174
  }
180
175
  }
181
176
  if (!(job instanceof import_database.Model)) {
182
- job.upstreamId = prevJob instanceof import_database.Model ? prevJob.get("id") : null;
183
177
  job.nodeId = node.id;
184
178
  job.nodeKey = node.key;
185
179
  }
186
- const savedJob = await this.saveJob(job);
180
+ const savedJob = this.saveJob(job);
187
181
  this.logger.info(
188
182
  `execution (${this.execution.id}) run instruction [${node.type}] for node (${node.id}) finished as status: ${savedJob.status}`
189
183
  );
@@ -230,6 +224,30 @@ class Processor {
230
224
  return this.exec(instruction.resume.bind(instruction), node, job);
231
225
  }
232
226
  async exit(s) {
227
+ if (this.jobsToSave.size) {
228
+ const newJobs = [];
229
+ for (const job of this.jobsToSave.values()) {
230
+ if (job.isNewRecord) {
231
+ newJobs.push(job);
232
+ } else {
233
+ await job.save({ transaction: this.mainTransaction });
234
+ }
235
+ }
236
+ if (newJobs.length) {
237
+ const JobsModel = this.options.plugin.db.getModel("jobs");
238
+ await JobsModel.bulkCreate(
239
+ newJobs.map((job) => job.toJSON()),
240
+ {
241
+ transaction: this.mainTransaction,
242
+ returning: false
243
+ }
244
+ );
245
+ for (const job of newJobs) {
246
+ job.isNewRecord = false;
247
+ }
248
+ }
249
+ this.jobsToSave.clear();
250
+ }
233
251
  if (typeof s === "number") {
234
252
  const status = this.constructor.StatusMap[s] ?? Math.sign(s);
235
253
  await this.execution.update({ status }, { transaction: this.mainTransaction });
@@ -240,32 +258,29 @@ class Processor {
240
258
  this.logger.info(`execution (${this.execution.id}) exiting with status ${this.execution.status}`);
241
259
  return null;
242
260
  }
243
- // TODO(optimize)
244
261
  /**
245
262
  * @experimental
246
263
  */
247
- async saveJob(payload) {
264
+ saveJob(payload) {
248
265
  const { database } = this.execution.constructor;
249
- const { mainTransaction: transaction } = this;
250
266
  const { model } = database.getCollection("jobs");
251
267
  let job;
252
268
  if (payload instanceof model) {
253
- job = await payload.save({ transaction });
254
- } else if (payload.id) {
255
- job = await model.findByPk(payload.id, { transaction });
256
- await job.update(payload, { transaction });
269
+ job = payload;
270
+ job.set("updatedAt", /* @__PURE__ */ new Date());
257
271
  } else {
258
- job = await model.create(
259
- {
260
- ...payload,
261
- executionId: this.execution.id
262
- },
263
- { transaction }
264
- );
272
+ job = model.build({
273
+ ...payload,
274
+ id: this.options.plugin.snowflake.getUniqueID().toString(),
275
+ createdAt: /* @__PURE__ */ new Date(),
276
+ updatedAt: /* @__PURE__ */ new Date(),
277
+ executionId: this.execution.id
278
+ });
265
279
  }
266
- this.jobsMap.set(job.id, job);
280
+ this.jobsToSave.set(job.id, job);
267
281
  this.lastSavedJob = job;
268
- this.jobsMapByNodeKey[job.nodeKey] = job.result;
282
+ this.jobsMapByNodeKey[job.nodeKey] = job;
283
+ this.jobResultsMapByNodeKey[job.nodeKey] = job.result;
269
284
  return job;
270
285
  }
271
286
  /**
@@ -319,31 +334,19 @@ class Processor {
319
334
  * @experimental
320
335
  */
321
336
  findBranchParentJob(job, node) {
322
- for (let j = job; j; j = this.jobsMap.get(j.upstreamId)) {
323
- if (j.nodeId === node.id) {
324
- return j;
325
- }
326
- }
327
- return null;
337
+ return this.jobsMapByNodeKey[node.key];
328
338
  }
329
339
  /**
330
340
  * @experimental
331
341
  */
332
342
  findBranchLastJob(node, job) {
333
- const allJobs = Array.from(this.jobsMap.values());
343
+ const allJobs = Object.values(this.jobsMapByNodeKey);
334
344
  const branchJobs = [];
335
345
  for (let n = this.findBranchEndNode(node); n && n !== node.upstream; n = n.upstream) {
336
346
  branchJobs.push(...allJobs.filter((item) => item.nodeId === n.id));
337
347
  }
338
- branchJobs.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
339
- for (let i = branchJobs.length - 1; i >= 0; i -= 1) {
340
- for (let j = branchJobs[i]; j && j.id !== job.id; j = this.jobsMap.get(j.upstreamId)) {
341
- if (j.upstreamId === job.id) {
342
- return branchJobs[i];
343
- }
344
- }
345
- }
346
- return null;
348
+ branchJobs.sort((a, b) => a.updatedAt.getTime() - b.updatedAt.getTime());
349
+ return branchJobs[branchJobs.length - 1] || null;
347
350
  }
348
351
  /**
349
352
  * @experimental
@@ -362,12 +365,12 @@ class Processor {
362
365
  for (let n = includeSelfScope ? node : this.findBranchParentNode(node); n; n = this.findBranchParentNode(n)) {
363
366
  const instruction = this.options.plugin.instructions.get(n.type);
364
367
  if (typeof (instruction == null ? void 0 : instruction.getScope) === "function") {
365
- $scopes[n.id] = $scopes[n.key] = instruction.getScope(n, this.jobsMapByNodeKey[n.key], this);
368
+ $scopes[n.id] = $scopes[n.key] = instruction.getScope(n, this.jobResultsMapByNodeKey[n.key], this);
366
369
  }
367
370
  }
368
371
  return {
369
372
  $context: this.execution.context,
370
- $jobsMapByNodeKey: this.jobsMapByNodeKey,
373
+ $jobsMapByNodeKey: this.jobResultsMapByNodeKey,
371
374
  $system: systemFns,
372
375
  $scopes,
373
376
  $env: this.options.plugin.app.environment.getVariables()
@@ -51,7 +51,9 @@ async function create(context, next) {
51
51
  const { whitelist, blacklist, updateAssociationValues, values, associatedIndex: workflowId } = context.action.params;
52
52
  context.body = await db.sequelize.transaction(async (transaction) => {
53
53
  const workflow = await repository.getSourceModel(transaction);
54
- if (workflow.executed) {
54
+ workflow.versionStats = await workflow.getVersionStats({ transaction });
55
+ const { executed } = workflow.versionStats;
56
+ if (executed) {
55
57
  context.throw(400, "Node could not be created in executed workflow");
56
58
  }
57
59
  const instance = await repository.create({
@@ -143,9 +145,9 @@ async function destroy(context, next) {
143
145
  const instance = await repository.findOne({
144
146
  filterByTk,
145
147
  fields: [...fields, "workflowId"],
146
- appends: ["upstream", "downstream", "workflow"]
148
+ appends: ["upstream", "downstream", "workflow.versionStats.executed"]
147
149
  });
148
- if (instance.workflow.executed) {
150
+ if (instance.workflow.versionStats.executed) {
149
151
  context.throw(400, "Nodes in executed workflow could not be deleted");
150
152
  }
151
153
  await db.sequelize.transaction(async (transaction) => {
@@ -202,10 +204,10 @@ async function update(context, next) {
202
204
  context.body = await db.sequelize.transaction(async (transaction) => {
203
205
  const { workflow } = await repository.findOne({
204
206
  filterByTk,
205
- appends: ["workflow.executed"],
207
+ appends: ["workflow.versionStats.executed"],
206
208
  transaction
207
209
  });
208
- if (workflow.executed) {
210
+ if (workflow.versionStats.executed) {
209
211
  context.throw(400, "Nodes in executed workflow could not be reconfigured");
210
212
  }
211
213
  return repository.update({
@@ -29,15 +29,17 @@ __export(workflowTasks_exports, {
29
29
  countMine: () => countMine
30
30
  });
31
31
  module.exports = __toCommonJS(workflowTasks_exports);
32
+ var import_sequelize = require("sequelize");
32
33
  var import_actions = require("@nocobase/actions");
33
34
  async function countMine(context, next) {
34
35
  const repository = import_actions.utils.getRepositoryFromParams(context);
35
36
  context.body = await repository.countAll({
36
37
  where: {
37
- userId: context.state.currentUser.id
38
+ userId: context.state.currentUser.id,
39
+ workflowId: { [import_sequelize.Op.ne]: null }
38
40
  }
39
41
  }) || [];
40
- next();
42
+ await next();
41
43
  }
42
44
  // Annotate the CommonJS export names for ESM import in node:
43
45
  0 && (module.exports = {
@@ -53,8 +53,11 @@ async function update(context, next) {
53
53
  whitelist: ["title", "description", "enabled", "triggerTitle", "config", "options"]
54
54
  });
55
55
  if (Object.keys(values).includes("config")) {
56
- const workflow = await repository.findById(filterByTk);
57
- if (workflow.get("executed")) {
56
+ const workflow = await repository.findOne({
57
+ filterByTk,
58
+ appends: ["versionStats"]
59
+ });
60
+ if (workflow.versionStats.executed) {
58
61
  return context.throw(400, "config of executed workflow can not be updated");
59
62
  }
60
63
  }
@@ -7,9 +7,11 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
+ var __create = Object.create;
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
13
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
14
16
  var __export = (target, all) => {
15
17
  for (var name in all)
@@ -23,53 +25,19 @@ var __copyProps = (to, from, except, desc) => {
23
25
  }
24
26
  return to;
25
27
  };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
26
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
37
  var executions_exports = {};
28
38
  __export(executions_exports, {
29
39
  default: () => executions_default
30
40
  });
31
41
  module.exports = __toCommonJS(executions_exports);
32
- var executions_default = {
33
- dumpRules: {
34
- group: "log"
35
- },
36
- migrationRules: ["schema-only"],
37
- name: "executions",
38
- shared: true,
39
- fields: [
40
- {
41
- type: "belongsTo",
42
- name: "workflow"
43
- },
44
- {
45
- type: "string",
46
- name: "key"
47
- },
48
- {
49
- type: "string",
50
- name: "eventKey",
51
- unique: true
52
- },
53
- {
54
- type: "hasMany",
55
- name: "jobs",
56
- onDelete: "CASCADE"
57
- },
58
- {
59
- type: "json",
60
- name: "context"
61
- },
62
- {
63
- type: "integer",
64
- name: "status"
65
- },
66
- {
67
- type: "json",
68
- name: "stack"
69
- },
70
- {
71
- type: "json",
72
- name: "output"
73
- }
74
- ]
75
- };
42
+ var import_executions = __toESM(require("../../common/collections/executions"));
43
+ var executions_default = import_executions.default;