@nocobase/plugin-workflow 2.2.0-alpha.10 → 2.2.0-alpha.12

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 (43) hide show
  1. package/dist/client/438.8bd46a04ca080a4e.js +10 -0
  2. package/dist/client/{509.88792f5bd054b2af.js → 509.3a4ac27f10833c75.js} +1 -1
  3. package/dist/client/{67.56a3d15a55ab7d5c.js → 67.5eb8767a709f27d9.js} +1 -1
  4. package/dist/client/828.d03ecfc4ac66e0f8.js +10 -0
  5. package/dist/client/87.b62b1123d4d560fb.js +10 -0
  6. package/dist/client/WorkflowTasks.d.ts +26 -3
  7. package/dist/client/index.d.ts +1 -1
  8. package/dist/client/index.js +1 -1
  9. package/dist/client-v2/{387.5e61d648d16dbf1b.js → 387.e002f8eb34aa77e3.js} +1 -1
  10. package/dist/client-v2/438.1459f1a7cd19ea4f.js +10 -0
  11. package/dist/client-v2/513.18e257b3025d7692.js +10 -0
  12. package/dist/client-v2/{677.7382807126d9621a.js → 677.7007f4a6a4640165.js} +1 -1
  13. package/dist/client-v2/constants.d.ts +4 -4
  14. package/dist/client-v2/index.js +1 -1
  15. package/dist/client-v2/legacySettingsRedirect.d.ts +15 -0
  16. package/dist/client-v2/plugin.d.ts +1 -1
  17. package/dist/common/collections/userWorkflowTaskStats.d.ts +54 -0
  18. package/dist/common/collections/userWorkflowTaskStats.js +87 -0
  19. package/dist/externalVersion.js +13 -13
  20. package/dist/locale/en-US.json +4 -0
  21. package/dist/locale/zh-CN.json +4 -0
  22. package/dist/node_modules/cron-parser/package.json +1 -1
  23. package/dist/node_modules/joi/package.json +1 -1
  24. package/dist/node_modules/lru-cache/package.json +1 -1
  25. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  26. package/dist/server/Plugin.d.ts +41 -4
  27. package/dist/server/Plugin.js +297 -2
  28. package/dist/server/Processor.js +11 -7
  29. package/dist/server/actions/index.js +3 -1
  30. package/dist/server/actions/userWorkflowTaskStats.d.ts +10 -0
  31. package/dist/server/actions/userWorkflowTaskStats.js +112 -0
  32. package/dist/server/actions/workflows.js +17 -0
  33. package/dist/server/collections/userWorkflowTaskStats.d.ts +11 -0
  34. package/dist/server/collections/userWorkflowTaskStats.js +43 -0
  35. package/dist/server/index.d.ts +1 -0
  36. package/dist/swagger/index.d.ts +68 -1
  37. package/dist/swagger/index.js +61 -1
  38. package/package.json +2 -2
  39. package/dist/client/438.6c6409d821d8c353.js +0 -10
  40. package/dist/client/828.6880ab21513b1968.js +0 -10
  41. package/dist/client/87.083467b89aaf3e53.js +0 -10
  42. package/dist/client-v2/438.b7df0416b66f8f64.js +0 -10
  43. package/dist/client-v2/513.617697f74783a611.js +0 -10
@@ -42,6 +42,7 @@ __export(Plugin_exports, {
42
42
  module.exports = __toCommonJS(Plugin_exports);
43
43
  var import_path = __toESM(require("path"));
44
44
  var import_nodejs_snowflake = require("nodejs-snowflake");
45
+ var import_sequelize = require("sequelize");
45
46
  var import_lru_cache = require("lru-cache");
46
47
  var import_database = require("@nocobase/database");
47
48
  var import_server = require("@nocobase/server");
@@ -83,6 +84,7 @@ class PluginWorkflowServer extends import_server.Plugin {
83
84
  loggerCache;
84
85
  meter = null;
85
86
  checker = null;
87
+ taskStatsProviders = /* @__PURE__ */ new Map();
86
88
  onBeforeSave = async (instance, { transaction, cycling }) => {
87
89
  if (cycling) {
88
90
  return;
@@ -393,6 +395,7 @@ class PluginWorkflowServer extends import_server.Plugin {
393
395
  actions: ["workflows:list"]
394
396
  });
395
397
  this.app.acl.allow("userWorkflowTasks", "listMine", "loggedIn");
398
+ this.app.acl.allow("userWorkflowTaskStats", "listMine", "loggedIn");
396
399
  db.on("workflows.beforeSave", this.onBeforeSave);
397
400
  db.on("workflows.afterCreate", this.onAfterCreate);
398
401
  db.on("workflows.afterUpdate", this.onAfterUpdate);
@@ -538,12 +541,304 @@ class PluginWorkflowServer extends import_server.Plugin {
538
541
  return db.sequelize.transaction();
539
542
  }
540
543
  }
544
+ registerTaskStatsProvider(type, provider) {
545
+ this.taskStatsProviders.set(type, provider);
546
+ }
547
+ async getWorkflowIdsByKey(workflowKey, transaction) {
548
+ const WorkflowRepo = this.db.getRepository("workflows");
549
+ const workflows = await WorkflowRepo.find({
550
+ filter: {
551
+ key: workflowKey
552
+ },
553
+ fields: ["id"],
554
+ transaction
555
+ });
556
+ return workflows.map((workflow) => workflow.id);
557
+ }
558
+ buildTaskStatsFilter(options) {
559
+ var _a, _b, _c;
560
+ const filter = {};
561
+ if ((_a = options.userIds) == null ? void 0 : _a.length) {
562
+ filter.userId = options.userIds;
563
+ }
564
+ if ((_b = options.workflowKeys) == null ? void 0 : _b.length) {
565
+ filter.workflowKey = options.workflowKeys;
566
+ }
567
+ if ((_c = options.types) == null ? void 0 : _c.length) {
568
+ filter.type = options.types;
569
+ }
570
+ return filter;
571
+ }
572
+ normalizeTaskStats(stats = {}) {
573
+ return {
574
+ pending: Number(stats.pending) || 0,
575
+ all: Number(stats.all) || 0
576
+ };
577
+ }
578
+ async upsertTaskStatsRow(row, transaction) {
579
+ const repository = this.db.getRepository("userWorkflowTaskStats");
580
+ const values = {
581
+ userId: row.userId,
582
+ workflowKey: row.workflowKey,
583
+ type: row.type,
584
+ ...this.normalizeTaskStats(row)
585
+ };
586
+ const record = await repository.findOne({
587
+ filter: {
588
+ userId: row.userId,
589
+ workflowKey: row.workflowKey,
590
+ type: row.type
591
+ },
592
+ transaction
593
+ });
594
+ if (record) {
595
+ await record.update(values, { transaction });
596
+ return record;
597
+ }
598
+ return repository.create({
599
+ values,
600
+ transaction
601
+ });
602
+ }
603
+ async refreshUserWorkflowTaskTypeStats(userId, type, { transaction } = {}) {
604
+ const repository = this.db.getRepository("userWorkflowTaskStats");
605
+ const rows = await repository.find({
606
+ filter: {
607
+ userId,
608
+ type
609
+ },
610
+ fields: ["pending", "all"],
611
+ transaction
612
+ });
613
+ const stats = rows.reduce(
614
+ (result, row) => ({
615
+ pending: result.pending + (Number(row.pending) || 0),
616
+ all: result.all + (Number(row.all) || 0)
617
+ }),
618
+ { pending: 0, all: 0 }
619
+ );
620
+ await this.updateTasksStats(userId, type, stats, { transaction });
621
+ return stats;
622
+ }
623
+ async refreshUserWorkflowTaskWorkflowStats(userId, workflowKey, { transaction } = {}) {
624
+ const repository = this.db.getRepository("userWorkflowTaskStats");
625
+ const rows = await repository.find({
626
+ filter: {
627
+ userId,
628
+ workflowKey
629
+ },
630
+ fields: ["pending", "all"],
631
+ transaction
632
+ });
633
+ return rows.reduce(
634
+ (result, row) => ({
635
+ pending: result.pending + (Number(row.pending) || 0),
636
+ all: result.all + (Number(row.all) || 0)
637
+ }),
638
+ { pending: 0, all: 0 }
639
+ );
640
+ }
641
+ sendTaskWorkflowStatsUpdated(userId, workflowKey, stats) {
642
+ if (!userId) {
643
+ return;
644
+ }
645
+ this.app.emit("ws:sendToUser", {
646
+ userId,
647
+ message: {
648
+ type: "workflow:taskWorkflowStats:updated",
649
+ payload: {
650
+ userId,
651
+ workflowKey,
652
+ stats
653
+ }
654
+ }
655
+ });
656
+ }
657
+ async updateTaskStatsByWorkflow(input, { transaction } = {}) {
658
+ await this.upsertTaskStatsRow(
659
+ {
660
+ userId: input.userId,
661
+ workflowKey: input.workflowKey,
662
+ type: input.type,
663
+ ...this.normalizeTaskStats(input.stats)
664
+ },
665
+ transaction
666
+ );
667
+ await this.refreshUserWorkflowTaskTypeStats(input.userId, input.type, { transaction });
668
+ const workflowStats = await this.refreshUserWorkflowTaskWorkflowStats(input.userId, input.workflowKey, {
669
+ transaction
670
+ });
671
+ this.sendTaskWorkflowStatsUpdated(input.userId, input.workflowKey, workflowStats);
672
+ }
673
+ async repairTaskStats(options = {}) {
674
+ const run = async (transaction) => {
675
+ var _a, _b;
676
+ const repository = this.db.getRepository("userWorkflowTaskStats");
677
+ const TaskStatsModel = this.db.getModel("userWorkflowTaskStats");
678
+ const filter = this.buildTaskStatsFilter(options);
679
+ const existedRows = await repository.find({
680
+ filter,
681
+ fields: ["userId", "workflowKey", "type"],
682
+ transaction
683
+ });
684
+ const providers = Array.from(this.taskStatsProviders.entries()).filter(([type]) => {
685
+ var _a2;
686
+ return !((_a2 = options.types) == null ? void 0 : _a2.length) || options.types.includes(type);
687
+ });
688
+ const legacyRows = providers.length ? await this.db.getRepository("userWorkflowTasks").find({
689
+ filter: {
690
+ ...((_a = options.userIds) == null ? void 0 : _a.length) ? { userId: options.userIds } : {},
691
+ type: providers.map(([type]) => type)
692
+ },
693
+ fields: ["userId", "type"],
694
+ transaction
695
+ }) : [];
696
+ const collectedRows = (await Promise.all(
697
+ providers.map(([, provider]) => provider.collectTaskStats({ ...options, transaction }, { plugin: this }))
698
+ )).flat();
699
+ const rows = collectedRows.filter((row) => {
700
+ var _a2, _b2, _c;
701
+ if (((_a2 = options.userIds) == null ? void 0 : _a2.length) && !options.userIds.includes(row.userId)) {
702
+ return false;
703
+ }
704
+ if (((_b2 = options.workflowKeys) == null ? void 0 : _b2.length) && !options.workflowKeys.includes(row.workflowKey)) {
705
+ return false;
706
+ }
707
+ if (((_c = options.types) == null ? void 0 : _c.length) && !options.types.includes(row.type)) {
708
+ return false;
709
+ }
710
+ return true;
711
+ });
712
+ await repository.destroy({
713
+ filter,
714
+ transaction
715
+ });
716
+ const batchSize = 1e3;
717
+ for (let offset = 0; offset < rows.length; offset += batchSize) {
718
+ await TaskStatsModel.bulkCreate(rows.slice(offset, offset + batchSize), {
719
+ returning: false,
720
+ transaction
721
+ });
722
+ }
723
+ const typePairs = /* @__PURE__ */ new Set();
724
+ const workflowPairs = /* @__PURE__ */ new Set();
725
+ if ((_b = options.userIds) == null ? void 0 : _b.length) {
726
+ for (const userId of options.userIds) {
727
+ for (const [type] of providers) {
728
+ typePairs.add(`${userId}\0${type}`);
729
+ }
730
+ for (const workflowKey of options.workflowKeys ?? []) {
731
+ workflowPairs.add(`${userId}\0${workflowKey}`);
732
+ }
733
+ }
734
+ }
735
+ for (const row of legacyRows) {
736
+ typePairs.add(`${row.userId}\0${row.type}`);
737
+ }
738
+ for (const row of [...existedRows, ...rows]) {
739
+ typePairs.add(`${row.userId}\0${row.type}`);
740
+ workflowPairs.add(`${row.userId}\0${row.workflowKey}`);
741
+ }
742
+ const affectedUserIds = Array.from(typePairs, (pair) => Number(pair.slice(0, pair.indexOf("\0"))));
743
+ const affectedTypes = Array.from(typePairs, (pair) => pair.slice(pair.indexOf("\0") + 1));
744
+ const categorizedRows = typePairs.size ? await TaskStatsModel.findAll({
745
+ attributes: ["userId", "type", [(0, import_sequelize.fn)("SUM", (0, import_sequelize.col)("pending")), "pending"], [(0, import_sequelize.fn)("SUM", (0, import_sequelize.col)("all")), "all"]],
746
+ where: {
747
+ userId: Array.from(new Set(affectedUserIds)),
748
+ type: Array.from(new Set(affectedTypes))
749
+ },
750
+ group: ["userId", "type"],
751
+ raw: true,
752
+ transaction
753
+ }) : [];
754
+ const categorizedMap = new Map(
755
+ categorizedRows.map((row) => [
756
+ `${row.userId}\0${row.type}`,
757
+ this.normalizeTaskStats({ pending: row.pending, all: row.all })
758
+ ])
759
+ );
760
+ const categorizedValues = Array.from(typePairs, (pair) => {
761
+ const separatorIndex = pair.indexOf("\0");
762
+ return {
763
+ userId: Number(pair.slice(0, separatorIndex)),
764
+ type: pair.slice(separatorIndex + 1),
765
+ stats: categorizedMap.get(pair) ?? { pending: 0, all: 0 }
766
+ };
767
+ });
768
+ const categorizedUserIds = Array.from(new Set(affectedUserIds));
769
+ const categorizedTypes = Array.from(new Set(affectedTypes));
770
+ if (categorizedUserIds.length && categorizedTypes.length) {
771
+ await this.db.getRepository("userWorkflowTasks").destroy({
772
+ filter: {
773
+ userId: categorizedUserIds,
774
+ type: categorizedTypes
775
+ },
776
+ transaction
777
+ });
778
+ }
779
+ const UserTasksModel = this.db.getModel("userWorkflowTasks");
780
+ for (let offset = 0; offset < categorizedValues.length; offset += batchSize) {
781
+ await UserTasksModel.bulkCreate(categorizedValues.slice(offset, offset + batchSize), {
782
+ returning: false,
783
+ transaction
784
+ });
785
+ }
786
+ if (options.silent) {
787
+ return;
788
+ }
789
+ for (const value of categorizedValues) {
790
+ if (!value.userId) {
791
+ continue;
792
+ }
793
+ this.app.emit("ws:sendToUser", {
794
+ userId: value.userId,
795
+ message: { type: "workflow:tasks:updated", payload: value }
796
+ });
797
+ }
798
+ const affectedWorkflowUserIds = Array.from(workflowPairs, (pair) => Number(pair.slice(0, pair.indexOf("\0"))));
799
+ const affectedWorkflowKeys = Array.from(workflowPairs, (pair) => pair.slice(pair.indexOf("\0") + 1));
800
+ const workflowRows = workflowPairs.size ? await TaskStatsModel.findAll({
801
+ attributes: [
802
+ "userId",
803
+ "workflowKey",
804
+ [(0, import_sequelize.fn)("SUM", (0, import_sequelize.col)("pending")), "pending"],
805
+ [(0, import_sequelize.fn)("SUM", (0, import_sequelize.col)("all")), "all"]
806
+ ],
807
+ where: {
808
+ userId: Array.from(new Set(affectedWorkflowUserIds)),
809
+ workflowKey: Array.from(new Set(affectedWorkflowKeys))
810
+ },
811
+ group: ["userId", "workflowKey"],
812
+ raw: true,
813
+ transaction
814
+ }) : [];
815
+ const workflowMap = new Map(
816
+ workflowRows.map((row) => [
817
+ `${row.userId}\0${row.workflowKey}`,
818
+ this.normalizeTaskStats({ pending: row.pending, all: row.all })
819
+ ])
820
+ );
821
+ for (const pair of workflowPairs) {
822
+ const separatorIndex = pair.indexOf("\0");
823
+ const userId = Number(pair.slice(0, separatorIndex));
824
+ const workflowKey = pair.slice(separatorIndex + 1);
825
+ this.sendTaskWorkflowStatsUpdated(userId, workflowKey, workflowMap.get(pair) ?? { pending: 0, all: 0 });
826
+ }
827
+ };
828
+ if (options.transaction) {
829
+ await run(options.transaction);
830
+ return;
831
+ }
832
+ await this.db.sequelize.transaction(run);
833
+ }
541
834
  /**
542
835
  * @experimental
836
+ * @deprecated Use updateTaskStatsByWorkflow() when workflowKey is available.
543
837
  */
544
838
  async updateTasksStats(userId, type, stats = { pending: 0, all: 0 }, { transaction }) {
545
839
  const { db } = this.app;
546
840
  const repository = db.getRepository("userWorkflowTasks");
841
+ const normalizedStats = this.normalizeTaskStats(stats);
547
842
  let record = await repository.findOne({
548
843
  filter: {
549
844
  userId,
@@ -554,7 +849,7 @@ class PluginWorkflowServer extends import_server.Plugin {
554
849
  if (record) {
555
850
  await record.update(
556
851
  {
557
- stats
852
+ stats: normalizedStats
558
853
  },
559
854
  { transaction }
560
855
  );
@@ -563,7 +858,7 @@ class PluginWorkflowServer extends import_server.Plugin {
563
858
  values: {
564
859
  userId,
565
860
  type,
566
- stats
861
+ stats: normalizedStats
567
862
  },
568
863
  transaction
569
864
  });
@@ -46,6 +46,7 @@ var import_utils = require("@nocobase/utils");
46
46
  var import_set = __toESM(require("lodash/set"));
47
47
  var import_constants = require("./constants");
48
48
  var import_timeout_errors = require("./timeout-errors");
49
+ const JOB_SAVE_BATCH_SIZE = 100;
49
50
  const OPEN_SCOPE_PENDING_ERROR = "Pending jobs are not allowed inside an open transaction scope";
50
51
  class Processor {
51
52
  constructor(execution, options) {
@@ -488,14 +489,17 @@ class Processor {
488
489
  }
489
490
  if (newJobs.length) {
490
491
  const JobsModel = this.options.plugin.db.getModel("jobs");
491
- await JobsModel.bulkCreate(
492
- newJobs.map((job) => job.toJSON()),
493
- {
494
- returning: false
492
+ for (let offset = 0; offset < newJobs.length; offset += JOB_SAVE_BATCH_SIZE) {
493
+ const batch = newJobs.slice(offset, offset + JOB_SAVE_BATCH_SIZE);
494
+ await JobsModel.bulkCreate(
495
+ batch.map((job) => job.toJSON()),
496
+ {
497
+ returning: false
498
+ }
499
+ );
500
+ for (const job of batch) {
501
+ job.isNewRecord = false;
495
502
  }
496
- );
497
- for (const job of newJobs) {
498
- job.isNewRecord = false;
499
503
  }
500
504
  }
501
505
  this.jobsToSave.clear();
@@ -44,6 +44,7 @@ var nodes = __toESM(require("./nodes"));
44
44
  var jobs = __toESM(require("./jobs"));
45
45
  var executions = __toESM(require("./executions"));
46
46
  var userWorkflowTasks = __toESM(require("./userWorkflowTasks"));
47
+ var userWorkflowTaskStats = __toESM(require("./userWorkflowTaskStats"));
47
48
  function make(name, mod) {
48
49
  return Object.keys(mod).reduce(
49
50
  (result, key) => ({
@@ -69,6 +70,7 @@ function actions_default({ app }) {
69
70
  }),
70
71
  ...make("jobs", jobs),
71
72
  ...make("executions", executions),
72
- ...make("userWorkflowTasks", userWorkflowTasks)
73
+ ...make("userWorkflowTasks", userWorkflowTasks),
74
+ ...make("userWorkflowTaskStats", userWorkflowTaskStats)
73
75
  });
74
76
  }
@@ -0,0 +1,10 @@
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
+ import { Context } from '@nocobase/actions';
10
+ export declare function listMine(context: Context, next: any): Promise<void>;
@@ -0,0 +1,112 @@
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 userWorkflowTaskStats_exports = {};
28
+ __export(userWorkflowTaskStats_exports, {
29
+ listMine: () => listMine
30
+ });
31
+ module.exports = __toCommonJS(userWorkflowTaskStats_exports);
32
+ var import_actions = require("@nocobase/actions");
33
+ async function listMine(context, next) {
34
+ const { type, search } = context.action.params;
35
+ const normalizedSearch = typeof search === "string" ? search.trim() : "";
36
+ const page = Math.max(Number.parseInt(String(context.action.params.page ?? 1), 10) || 1, 1);
37
+ const pageSize = Math.min(
38
+ Math.max(Number.parseInt(String(context.action.params.pageSize ?? 200), 10) || 200, 1),
39
+ 200
40
+ );
41
+ const pagination = import_actions.utils.pageArgsToLimitArgs(page, pageSize);
42
+ const repository = context.db.getRepository("userWorkflowTaskStats");
43
+ const rows = await repository.find({
44
+ filter: {
45
+ userId: context.state.currentUser.id,
46
+ ...type ? { type } : {},
47
+ all: {
48
+ $gt: 0
49
+ }
50
+ },
51
+ fields: ["workflowKey", "pending", "all"]
52
+ });
53
+ const statsMap = /* @__PURE__ */ new Map();
54
+ for (const row of rows) {
55
+ if (!row.workflowKey) {
56
+ continue;
57
+ }
58
+ const existed = statsMap.get(row.workflowKey) ?? {
59
+ workflowKey: row.workflowKey,
60
+ stats: { pending: 0, all: 0 }
61
+ };
62
+ existed.stats.pending += Number(row.pending) || 0;
63
+ existed.stats.all += Number(row.all) || 0;
64
+ statsMap.set(row.workflowKey, existed);
65
+ }
66
+ const workflowKeys = Array.from(statsMap.keys());
67
+ if (!workflowKeys.length) {
68
+ context.body = {
69
+ rows: [],
70
+ page,
71
+ pageSize,
72
+ hasNext: false
73
+ };
74
+ await next();
75
+ return;
76
+ }
77
+ const workflows = await context.db.getRepository("workflows").find({
78
+ filter: {
79
+ key: workflowKeys,
80
+ current: true,
81
+ ...normalizedSearch ? {
82
+ title: {
83
+ $includes: normalizedSearch
84
+ }
85
+ } : {}
86
+ },
87
+ fields: ["key", "title"],
88
+ sort: ["title"],
89
+ limit: pagination.limit + 1,
90
+ offset: pagination.offset
91
+ });
92
+ const hasNext = workflows.length > pageSize;
93
+ const data = workflows.slice(0, pageSize).map((workflow) => {
94
+ var _a;
95
+ return {
96
+ workflowKey: workflow.key,
97
+ title: workflow.title,
98
+ stats: ((_a = statsMap.get(workflow.key)) == null ? void 0 : _a.stats) ?? { pending: 0, all: 0 }
99
+ };
100
+ });
101
+ context.body = {
102
+ rows: data,
103
+ page,
104
+ pageSize,
105
+ hasNext
106
+ };
107
+ await next();
108
+ }
109
+ // Annotate the CommonJS export names for ESM import in node:
110
+ 0 && (module.exports = {
111
+ listMine
112
+ });
@@ -106,6 +106,7 @@ async function update(context, next) {
106
106
  return import_actions.default.update(context, next);
107
107
  }
108
108
  async function destroy(context, next) {
109
+ const plugin = context.app.pm.get(import_Plugin.default);
109
110
  const repository = import_actions.utils.getRepositoryFromParams(context);
110
111
  const { filterByTk, filter } = context.action.params;
111
112
  await context.db.sequelize.transaction(async (transaction) => {
@@ -116,6 +117,15 @@ async function destroy(context, next) {
116
117
  transaction
117
118
  });
118
119
  const ids = new Set(items.map((item) => item.id));
120
+ const affectedKeys = Array.from(new Set(items.map((item) => item.get("key"))));
121
+ const affectedTaskStats = affectedKeys.length ? await context.db.getRepository("userWorkflowTaskStats").find({
122
+ filter: {
123
+ workflowKey: affectedKeys
124
+ },
125
+ fields: ["userId"],
126
+ transaction
127
+ }) : [];
128
+ const affectedUserIds = Array.from(new Set(affectedTaskStats.map((item) => item.get("userId"))));
119
129
  const keysSet = new Set(items.filter((item) => item.current).map((item) => item.key));
120
130
  const revisions = await repository.find({
121
131
  filter: {
@@ -138,6 +148,13 @@ async function destroy(context, next) {
138
148
  },
139
149
  transaction
140
150
  });
151
+ if (affectedKeys.length) {
152
+ await plugin.repairTaskStats({
153
+ workflowKeys: affectedKeys,
154
+ ...affectedUserIds.length ? { userIds: affectedUserIds } : {},
155
+ transaction
156
+ });
157
+ }
141
158
  context.body = deleted;
142
159
  });
143
160
  next();
@@ -0,0 +1,11 @@
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
+ import { CollectionOptions } from '@nocobase/database';
10
+ declare const _default: CollectionOptions;
11
+ export default _default;
@@ -0,0 +1,43 @@
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 __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
26
+ return to;
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
+ ));
36
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
+ var userWorkflowTaskStats_exports = {};
38
+ __export(userWorkflowTaskStats_exports, {
39
+ default: () => userWorkflowTaskStats_default
40
+ });
41
+ module.exports = __toCommonJS(userWorkflowTaskStats_exports);
42
+ var import_userWorkflowTaskStats = __toESM(require("../../common/collections/userWorkflowTaskStats"));
43
+ var userWorkflowTaskStats_default = import_userWorkflowTaskStats.default;
@@ -17,4 +17,5 @@ export type { EventOptions } from './Dispatcher';
17
17
  export { default as Processor } from './Processor';
18
18
  export type { BackgroundAbortHandle, ProcessorOptions, ScopeTransaction } from './Processor';
19
19
  export { default } from './Plugin';
20
+ export type { RepairTaskStatsOptions, TaskStatsProvider, TaskStatsRow } from './Plugin';
20
21
  export * from './types';