@nocobase/plugin-workflow 0.7.4-alpha.7 → 0.7.6-alpha.1

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.
@@ -56,23 +56,26 @@ ScheduleModes.set(SCHEDULE_MODE.CONSTANT, {
56
56
  endsOn = _workflow$config.endsOn,
57
57
  repeat = _workflow$config.repeat;
58
58
  const timestamp = now.getTime();
59
+ const startTime = Date.parse(startsOn);
59
60
 
60
- if (startsOn) {
61
- const startTime = Date.parse(startsOn);
62
-
63
- if (!startTime || startTime > timestamp + this.cacheCycle) {
64
- return false;
65
- }
61
+ if (!startTime || startTime > timestamp + this.cacheCycle) {
62
+ return false;
63
+ }
66
64
 
65
+ if (repeat) {
67
66
  if (typeof repeat === 'number' && repeat > this.cacheCycle && (timestamp - startTime) % repeat > this.cacheCycle) {
68
67
  return false;
69
68
  }
70
- }
71
69
 
72
- if (endsOn) {
73
- const endTime = Date.parse(endsOn);
70
+ if (endsOn) {
71
+ const endTime = Date.parse(endsOn);
74
72
 
75
- if (!endTime || endTime <= timestamp) {
73
+ if (!endTime || endTime <= timestamp) {
74
+ return false;
75
+ }
76
+ }
77
+ } else {
78
+ if (startTime < timestamp) {
76
79
  return false;
77
80
  }
78
81
  }
@@ -80,40 +83,45 @@ ScheduleModes.set(SCHEDULE_MODE.CONSTANT, {
80
83
  return true;
81
84
  },
82
85
 
83
- trigger(workflow, date) {
86
+ trigger(workflow, now) {
84
87
  const _workflow$config2 = workflow.config,
85
88
  startsOn = _workflow$config2.startsOn,
86
89
  endsOn = _workflow$config2.endsOn,
87
90
  repeat = _workflow$config2.repeat;
91
+ const timestamp = now.getTime();
92
+ const startTime = Math.floor(Date.parse(startsOn) / 1000) * 1000;
88
93
 
89
- if (startsOn && typeof repeat === 'number') {
90
- const startTime = Math.floor(Date.parse(startsOn) / 1000) * 1000;
94
+ if (repeat) {
95
+ if (typeof repeat === 'number') {
96
+ if (Math.round(timestamp - startTime) % repeat) {
97
+ return;
98
+ }
99
+ }
91
100
 
92
- if (Math.round(date.getTime() - startTime) % repeat) {
101
+ if (endsOn) {
102
+ const endTime = Date.parse(endsOn);
103
+
104
+ if (!endTime || endTime < timestamp) {
105
+ return false;
106
+ }
107
+ }
108
+ } else {
109
+ if (startTime !== timestamp) {
93
110
  return;
94
111
  }
95
112
  }
96
113
 
97
114
  return this.plugin.trigger(workflow, {
98
- date
115
+ date: now
99
116
  });
100
117
  }
101
118
 
102
119
  });
103
120
 
104
- function getDateRangeFilter(on, now, dir) {
105
- const timestamp = now.getTime();
106
- const op = dir < 0 ? _sequelize().Op.lt : _sequelize().Op.gte;
107
-
121
+ function getOnTimestampWithOffset(on, now) {
108
122
  switch (typeof on) {
109
123
  case 'string':
110
- const time = Date.parse(on);
111
-
112
- if (!time || (dir < 0 ? timestamp < time : time <= timestamp)) {
113
- return null;
114
- }
115
-
116
- break;
124
+ return Date.parse(on);
117
125
 
118
126
  case 'object':
119
127
  const field = on.field,
@@ -123,20 +131,17 @@ function getDateRangeFilter(on, now, dir) {
123
131
  unit = _on$unit === void 0 ? 1000 : _on$unit;
124
132
 
125
133
  if (!field) {
126
- return {};
134
+ return null;
127
135
  }
128
136
 
129
- return {
130
- [field]: {
131
- [op]: new Date(timestamp + offset * unit * dir)
132
- }
133
- };
137
+ const timestamp = now.getTime(); // onDate + offset > now
138
+ // onDate > now - offset
139
+
140
+ return timestamp - offset * unit;
134
141
 
135
142
  default:
136
- break;
143
+ return null;
137
144
  }
138
-
139
- return {};
140
145
  }
141
146
 
142
147
  function getDataOptionTime(data, on, dir = 1) {
@@ -151,7 +156,7 @@ function getDataOptionTime(data, on, dir = 1) {
151
156
  offset = _on$offset2 === void 0 ? 0 : _on$offset2,
152
157
  _on$unit2 = on.unit,
153
158
  unit = _on$unit2 === void 0 ? 1000 : _on$unit2;
154
- return data[field] ? data[field].getTime() - offset * unit * dir : null;
159
+ return data.get(field) ? data.get(field).getTime() - offset * unit * dir : null;
155
160
 
156
161
  default:
157
162
  return null;
@@ -189,49 +194,49 @@ ScheduleModes.set(SCHEDULE_MODE.COLLECTION_FIELD, {
189
194
  const event = `${collection}.afterSave`;
190
195
  const name = getHookId(workflow, event);
191
196
 
192
- if (!this.events.has(name)) {
193
- // NOTE: toggle cache depends on new date
194
- const listener = /*#__PURE__*/function () {
195
- var _ref = _asyncToGenerator(function* (data, options) {
196
- const now = new Date();
197
- now.setMilliseconds(0);
198
- const timestamp = now.getTime();
199
- const startTime = getDataOptionTime(data, startsOn);
200
- const endTime = getDataOptionTime(data, endsOn, -1);
201
-
202
- if (!startTime && !repeat) {
203
- return;
204
- }
197
+ if (this.events.has(name)) {
198
+ return;
199
+ } // NOTE: toggle cache depends on new date
205
200
 
206
- if (startTime && startTime > timestamp + _this.cacheCycle) {
207
- return;
208
- }
209
201
 
210
- if (endTime && endTime <= timestamp) {
211
- return;
212
- }
202
+ const listener = /*#__PURE__*/function () {
203
+ var _ref = _asyncToGenerator(function* (data, options) {
204
+ const now = new Date();
205
+ now.setMilliseconds(0);
206
+ const timestamp = now.getTime();
207
+ const startTime = getDataOptionTime(data, startsOn);
208
+ const endTime = getDataOptionTime(data, endsOn, -1);
213
209
 
214
- if (!nextInCycle.call(_this, workflow, now)) {
215
- return;
216
- }
210
+ if (!startTime && !repeat) {
211
+ return;
212
+ }
217
213
 
218
- if (typeof repeat === 'number' && repeat > _this.cacheCycle && (timestamp - startTime) % repeat > _this.cacheCycle) {
219
- return;
220
- }
214
+ if (startTime && startTime > timestamp + _this.cacheCycle) {
215
+ return;
216
+ }
221
217
 
222
- console.log('set cache', now);
218
+ if (endTime && endTime <= timestamp) {
219
+ return;
220
+ }
223
221
 
224
- _this.setCache(workflow);
225
- });
222
+ if (!matchNext.call(_this, workflow, now)) {
223
+ return;
224
+ }
226
225
 
227
- return function listener(_x, _x2) {
228
- return _ref.apply(this, arguments);
229
- };
230
- }();
226
+ if (typeof repeat === 'number' && repeat > _this.cacheCycle && (timestamp - startTime) % repeat > _this.cacheCycle) {
227
+ return;
228
+ }
231
229
 
232
- this.events.set(name, listener);
233
- this.plugin.app.db.on(`${collection}.afterSave`, listener);
234
- }
230
+ _this.setCache(workflow);
231
+ });
232
+
233
+ return function listener(_x, _x2) {
234
+ return _ref.apply(this, arguments);
235
+ };
236
+ }();
237
+
238
+ this.events.set(name, listener);
239
+ this.plugin.app.db.on(event, listener);
235
240
  },
236
241
 
237
242
  off(workflow) {
@@ -242,7 +247,7 @@ ScheduleModes.set(SCHEDULE_MODE.COLLECTION_FIELD, {
242
247
  if (this.events.has(name)) {
243
248
  const listener = this.events.get(name);
244
249
  this.events.delete(name);
245
- this.plugin.app.db.off(`${collection}.afterSave`, listener);
250
+ this.plugin.app.db.off(event, listener);
246
251
  }
247
252
  },
248
253
 
@@ -250,34 +255,60 @@ ScheduleModes.set(SCHEDULE_MODE.COLLECTION_FIELD, {
250
255
  var _this2 = this;
251
256
 
252
257
  return _asyncToGenerator(function* () {
258
+ const db = _this2.plugin.app.db;
253
259
  const _workflow$config4 = workflow.config,
254
260
  startsOn = _workflow$config4.startsOn,
255
261
  endsOn = _workflow$config4.endsOn,
256
262
  repeat = _workflow$config4.repeat,
257
263
  collection = _workflow$config4.collection;
258
- const starts = getDateRangeFilter(startsOn, now, -1);
264
+ const timestamp = now.getTime();
265
+ const startTimestamp = getOnTimestampWithOffset(startsOn, now);
259
266
 
260
- if (!starts || !Object.keys(starts).length) {
267
+ if (!startTimestamp) {
261
268
  return false;
262
269
  }
263
270
 
264
- const ends = getDateRangeFilter(endsOn, now, 1);
271
+ const conditions = [{
272
+ [startsOn.field]: {
273
+ [_sequelize().Op.lt]: new Date(startTimestamp + _this2.cacheCycle)
274
+ }
275
+ }]; // when repeat is number, means repeat after startsOn
276
+ // (now - startsOn) % repeat <= cacheCycle
265
277
 
266
- if (!ends) {
267
- return false;
268
- }
278
+ if (repeat) {
279
+ const tsFn = DialectTimestampFnMap[db.options.dialect];
269
280
 
270
- const conditions = [starts, ends].filter(item => Boolean(Object.keys(item).length)); // when repeat is number, means repeat after startsOn
271
- // (now - startsOn) % repeat <= cacheCycle
281
+ if (typeof repeat === 'number' && repeat > _this2.cacheCycle && tsFn) {
282
+ conditions.push((0, _sequelize().where)((0, _sequelize().fn)('MOD', (0, _sequelize().literal)(`${Math.round(timestamp / 1000)} - ${tsFn(startsOn.field)}`), Math.round(repeat / 1000)), {
283
+ [_sequelize().Op.lt]: Math.round(_this2.cacheCycle / 1000)
284
+ })); // conditions.push(literal(`mod(${timestamp} - ${tsFn(startsOn.field)} * 1000, ${repeat}) < ${this.cacheCycle}`));
285
+ }
272
286
 
273
- const db = _this2.plugin.app.db;
274
- const tsFn = DialectTimestampFnMap[db.options.dialect];
287
+ if (endsOn) {
288
+ const endTimestamp = getOnTimestampWithOffset(endsOn, now);
275
289
 
276
- if (repeat && typeof repeat === 'number' && repeat > _this2.cacheCycle && tsFn) {
277
- const uts = now.getTime();
278
- conditions.push((0, _sequelize().where)((0, _sequelize().fn)('MOD', (0, _sequelize().literal)(`${Math.round(uts / 1000)} - ${tsFn(startsOn.field)}`), Math.round(repeat / 1000)), {
279
- [_sequelize().Op.lt]: Math.round(_this2.cacheCycle / 1000)
280
- })); // conditions.push(literal(`mod(${uts} - ${tsFn(startsOn.field)} * 1000, ${repeat}) < ${this.cacheCycle}`));
290
+ if (!endTimestamp) {
291
+ return false;
292
+ }
293
+
294
+ if (typeof endsOn === 'string') {
295
+ if (endTimestamp <= timestamp) {
296
+ return false;
297
+ }
298
+ } else {
299
+ conditions.push({
300
+ [endsOn.field]: {
301
+ [_sequelize().Op.gte]: new Date(endTimestamp + _this2.interval)
302
+ }
303
+ });
304
+ }
305
+ }
306
+ } else {
307
+ conditions.push({
308
+ [startsOn.field]: {
309
+ [_sequelize().Op.gte]: new Date(startTimestamp)
310
+ }
311
+ });
281
312
  }
282
313
 
283
314
  const _db$getCollection = db.getCollection(collection),
@@ -292,35 +323,29 @@ ScheduleModes.set(SCHEDULE_MODE.COLLECTION_FIELD, {
292
323
  })();
293
324
  },
294
325
 
295
- trigger(workflow, date) {
326
+ trigger(workflow, now) {
296
327
  var _this3 = this;
297
328
 
298
329
  return _asyncToGenerator(function* () {
299
- var _startsOn$offset, _startsOn$unit;
300
-
301
330
  const _workflow$config5 = workflow.config,
302
- collection = _workflow$config5.collection,
303
331
  startsOn = _workflow$config5.startsOn,
332
+ repeat = _workflow$config5.repeat,
304
333
  endsOn = _workflow$config5.endsOn,
305
- repeat = _workflow$config5.repeat;
334
+ collection = _workflow$config5.collection;
335
+ const timestamp = now.getTime();
336
+ const startTimestamp = getOnTimestampWithOffset(startsOn, now);
306
337
 
307
- if (typeof startsOn !== 'object') {
308
- return;
338
+ if (!startTimestamp) {
339
+ return false;
309
340
  }
310
341
 
311
- const timestamp = date.getTime();
312
- const startTimestamp = timestamp - ((_startsOn$offset = startsOn.offset) !== null && _startsOn$offset !== void 0 ? _startsOn$offset : 0) * ((_startsOn$unit = startsOn.unit) !== null && _startsOn$unit !== void 0 ? _startsOn$unit : 1000);
313
- const conditions = [];
342
+ const conditions = [{
343
+ [startsOn.field]: {
344
+ [_sequelize().Op.lt]: new Date(startTimestamp + _this3.interval)
345
+ }
346
+ }];
314
347
 
315
- if (!repeat) {
316
- // startsOn exactly equal to now in 1s
317
- conditions.push({
318
- [startsOn.field]: {
319
- [_sequelize().Op.gte]: new Date(startTimestamp),
320
- [_sequelize().Op.lt]: new Date(startTimestamp + 1000)
321
- }
322
- });
323
- } else {
348
+ if (repeat) {
324
349
  // startsOn not after now
325
350
  conditions.push({
326
351
  [startsOn.field]: {
@@ -335,32 +360,32 @@ ScheduleModes.set(SCHEDULE_MODE.COLLECTION_FIELD, {
335
360
  })); // conditions.push(literal(`MOD(CAST(${timestamp} AS BIGINT) - CAST((FLOOR(${tsFn(startsOn.field)}) AS BIGINT) * 1000), ${repeat}) = 0`));
336
361
  }
337
362
 
338
- switch (typeof endsOn) {
339
- case 'string':
340
- const endTime = Date.parse(endsOn);
341
-
342
- if (!endTime || endTime <= timestamp) {
343
- return;
344
- }
345
-
346
- break;
363
+ if (endsOn) {
364
+ const endTimestamp = getOnTimestampWithOffset(endsOn, now);
347
365
 
348
- case 'object':
349
- if (endsOn.field) {
350
- var _endsOn$offset, _endsOn$unit;
366
+ if (!endTimestamp) {
367
+ return false;
368
+ }
351
369
 
352
- conditions.push({
353
- [endsOn.field]: {
354
- [_sequelize().Op.gte]: new Date(timestamp - ((_endsOn$offset = endsOn.offset) !== null && _endsOn$offset !== void 0 ? _endsOn$offset : 0) * ((_endsOn$unit = endsOn.unit) !== null && _endsOn$unit !== void 0 ? _endsOn$unit : 1000) + 1000)
355
- }
356
- });
370
+ if (typeof endsOn === 'string') {
371
+ if (endTimestamp <= timestamp) {
372
+ return false;
357
373
  }
358
-
359
- break;
360
-
361
- default:
362
- break;
374
+ } else {
375
+ conditions.push({
376
+ [endsOn.field]: {
377
+ [_sequelize().Op.gte]: new Date(endTimestamp + _this3.interval)
378
+ }
379
+ });
380
+ }
363
381
  }
382
+ } else {
383
+ // startsOn exactly equal to now in 1s
384
+ conditions.push({
385
+ [startsOn.field]: {
386
+ [_sequelize().Op.gte]: new Date(startTimestamp)
387
+ }
388
+ });
364
389
  }
365
390
 
366
391
  const _this3$plugin$app$db$ = _this3.plugin.app.db.getCollection(collection),
@@ -373,12 +398,12 @@ ScheduleModes.set(SCHEDULE_MODE.COLLECTION_FIELD, {
373
398
  });
374
399
 
375
400
  if (instances.length) {
376
- console.log(instances.length, 'rows trigger at', date);
401
+ console.log(instances.length, 'rows trigger at', now);
377
402
  }
378
403
 
379
404
  instances.forEach(item => {
380
405
  _this3.plugin.trigger(workflow, {
381
- date,
406
+ date: now,
382
407
  data: item.get()
383
408
  });
384
409
  });
@@ -387,24 +412,16 @@ ScheduleModes.set(SCHEDULE_MODE.COLLECTION_FIELD, {
387
412
 
388
413
  });
389
414
 
390
- function nextInCycle(workflow, now) {
415
+ function matchNext(workflow, now, range = this.cacheCycle) {
391
416
  const repeat = workflow.config.repeat; // no repeat means no need to rerun
392
417
  // but if in current cycle, should be put in cache
393
418
  // no repeat but in current cycle means startsOn has been configured
394
419
  // so we need to more info to determine if necessary config items
395
420
 
396
- if (!repeat) {
421
+ if (typeof repeat !== 'string') {
397
422
  return true;
398
423
  }
399
424
 
400
- switch (typeof repeat) {
401
- case 'string':
402
- break;
403
-
404
- default:
405
- return true;
406
- }
407
-
408
425
  const currentDate = new Date(now);
409
426
  currentDate.setMilliseconds(-1);
410
427
  const timestamp = now.getTime();
@@ -415,7 +432,7 @@ function nextInCycle(workflow, now) {
415
432
 
416
433
  let next = interval.next(); // NOTE: cache all workflows will be matched in current cycle
417
434
 
418
- if (next.getTime() - timestamp <= this.cacheCycle) {
435
+ if (next.getTime() - timestamp <= range) {
419
436
  return true;
420
437
  }
421
438
 
@@ -452,18 +469,20 @@ class ScheduleTrigger extends _.Trigger {
452
469
  }
453
470
 
454
471
  init() {
455
- if (!this.timer) {
456
- const now = new Date(); // NOTE: assign to this.timer to avoid duplicated initialization
457
-
458
- this.timer = setTimeout(() => {
459
- this.timer = setInterval(this.run, this.interval); // initially trigger
460
- // this.onTick(now);
461
- }, // NOTE:
462
- // try to align to system time on each second starts,
463
- // after at least 1 second initialized for anything to get ready.
464
- // so jobs in 2 seconds will be missed at first start.
465
- 1000 - now.getMilliseconds());
472
+ if (this.timer) {
473
+ return;
466
474
  }
475
+
476
+ const now = new Date(); // NOTE: assign to this.timer to avoid duplicated initialization
477
+
478
+ this.timer = setTimeout(() => {
479
+ this.timer = setInterval(this.run, this.interval); // initially trigger
480
+ // this.onTick(now);
481
+ }, // NOTE:
482
+ // try to align to system time on each second starts,
483
+ // after at least 1 second initialized for anything to get ready.
484
+ // so jobs in 2 seconds will be missed at first start.
485
+ 1000 - now.getMilliseconds());
467
486
  }
468
487
 
469
488
  onTick(now) {
@@ -631,13 +650,10 @@ class ScheduleTrigger extends _.Trigger {
631
650
  }
632
651
 
633
652
  exports.default = ScheduleTrigger;
634
- ScheduleTrigger.CacheRules = [// ({ enabled }) => enabled,
635
- ({
653
+ ScheduleTrigger.CacheRules = [({
636
654
  config,
637
655
  allExecuted
638
- }) => config.limit ? allExecuted < config.limit : true, ({
639
- config
640
- }) => ['repeat', 'startsOn'].some(key => config[key]), nextInCycle, function (workflow, now) {
656
+ }) => (config.limit ? allExecuted < config.limit : true) && config.startsOn, matchNext, function (workflow, now) {
641
657
  const mode = workflow.config.mode;
642
658
  const modeHandlers = ScheduleModes.get(mode);
643
659
  return modeHandlers.shouldCache.call(this, workflow, now);
@@ -645,28 +661,6 @@ ScheduleTrigger.CacheRules = [// ({ enabled }) => enabled,
645
661
  ScheduleTrigger.TriggerRules = [({
646
662
  config,
647
663
  allExecuted
648
- }) => config.limit ? allExecuted < config.limit : true, ({
649
- config
650
- }) => ['repeat', 'startsOn'].some(key => config[key]), function (workflow, now) {
651
- const repeat = workflow.config.repeat;
652
-
653
- if (typeof repeat !== 'string') {
654
- return true;
655
- }
656
-
657
- const currentDate = new Date(now);
658
- currentDate.setMilliseconds(-1);
659
- const timestamp = now.getTime();
660
-
661
- const interval = _cronParser().default.parseExpression(repeat, {
662
- currentDate
663
- });
664
-
665
- let next = interval.next();
666
-
667
- if (next.getTime() === timestamp) {
668
- return true;
669
- }
670
-
671
- return false;
664
+ }) => (config.limit ? allExecuted < config.limit : true) && config.startsOn, function (workflow, now) {
665
+ return matchNext.call(this, workflow, now, 0);
672
666
  }];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/plugin-workflow",
3
- "version": "0.7.4-alpha.7",
3
+ "version": "0.7.6-alpha.1",
4
4
  "main": "lib/index.js",
5
5
  "license": "Apache-2.0",
6
6
  "licenses": [
@@ -10,17 +10,17 @@
10
10
  }
11
11
  ],
12
12
  "dependencies": {
13
- "@nocobase/actions": "0.7.4-alpha.7",
14
- "@nocobase/client": "0.7.4-alpha.7",
15
- "@nocobase/database": "0.7.4-alpha.7",
16
- "@nocobase/server": "0.7.4-alpha.7",
17
- "@nocobase/utils": "0.7.4-alpha.7",
13
+ "@nocobase/actions": "0.7.6-alpha.1",
14
+ "@nocobase/client": "0.7.6-alpha.1",
15
+ "@nocobase/database": "0.7.6-alpha.1",
16
+ "@nocobase/server": "0.7.6-alpha.1",
17
+ "@nocobase/utils": "0.7.6-alpha.1",
18
18
  "cron-parser": "4.4.0",
19
19
  "json-templates": "^4.2.0",
20
20
  "react-js-cron": "^1.4.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@nocobase/test": "0.7.4-alpha.7"
23
+ "@nocobase/test": "0.7.6-alpha.1"
24
24
  },
25
- "gitHead": "77f22e6da464d19be111835316faf4b94cd80413"
25
+ "gitHead": "f20ce011a9ac516dc6aec110979f063a0e63f923"
26
26
  }
package/server.d.ts CHANGED
File without changes
package/server.js CHANGED
File without changes