@nocobase/plugin-workflow 2.2.0-alpha.11 → 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.
- package/dist/client/438.8bd46a04ca080a4e.js +10 -0
- package/dist/client/{509.88792f5bd054b2af.js → 509.3a4ac27f10833c75.js} +1 -1
- package/dist/client/{67.56a3d15a55ab7d5c.js → 67.5eb8767a709f27d9.js} +1 -1
- package/dist/client/828.d03ecfc4ac66e0f8.js +10 -0
- package/dist/client/87.b62b1123d4d560fb.js +10 -0
- package/dist/client/WorkflowTasks.d.ts +26 -3
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client-v2/{387.5e61d648d16dbf1b.js → 387.e002f8eb34aa77e3.js} +1 -1
- package/dist/client-v2/438.1459f1a7cd19ea4f.js +10 -0
- package/dist/client-v2/513.18e257b3025d7692.js +10 -0
- package/dist/client-v2/{677.7382807126d9621a.js → 677.7007f4a6a4640165.js} +1 -1
- package/dist/client-v2/constants.d.ts +4 -4
- package/dist/client-v2/index.js +1 -1
- package/dist/client-v2/legacySettingsRedirect.d.ts +15 -0
- package/dist/client-v2/plugin.d.ts +1 -1
- package/dist/common/collections/userWorkflowTaskStats.d.ts +54 -0
- package/dist/common/collections/userWorkflowTaskStats.js +87 -0
- package/dist/externalVersion.js +13 -13
- package/dist/locale/en-US.json +4 -0
- package/dist/locale/zh-CN.json +4 -0
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/joi/package.json +1 -1
- package/dist/node_modules/lru-cache/package.json +1 -1
- package/dist/node_modules/nodejs-snowflake/package.json +1 -1
- package/dist/server/Plugin.d.ts +41 -4
- package/dist/server/Plugin.js +297 -2
- package/dist/server/Processor.js +11 -7
- package/dist/server/actions/index.js +3 -1
- package/dist/server/actions/userWorkflowTaskStats.d.ts +10 -0
- package/dist/server/actions/userWorkflowTaskStats.js +112 -0
- package/dist/server/actions/workflows.js +17 -0
- package/dist/server/collections/userWorkflowTaskStats.d.ts +11 -0
- package/dist/server/collections/userWorkflowTaskStats.js +43 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/swagger/index.d.ts +68 -1
- package/dist/swagger/index.js +61 -1
- package/package.json +2 -2
- package/dist/client/438.6c6409d821d8c353.js +0 -10
- package/dist/client/828.6880ab21513b1968.js +0 -10
- package/dist/client/87.083467b89aaf3e53.js +0 -10
- package/dist/client-v2/438.b7df0416b66f8f64.js +0 -10
- package/dist/client-v2/513.617697f74783a611.js +0 -10
package/dist/server/Plugin.js
CHANGED
|
@@ -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
|
});
|
package/dist/server/Processor.js
CHANGED
|
@@ -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
|
-
|
|
492
|
-
newJobs.
|
|
493
|
-
|
|
494
|
-
|
|
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;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -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';
|