@nocobase/plugin-workflow-manual 2.3.0-alpha.1 → 3.0.0-alpha.2
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/WorkflowTodo.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +11 -11
- package/dist/node_modules/joi/package.json +1 -1
- package/dist/server/ManualInstruction.d.ts +4 -3
- package/dist/server/ManualInstruction.js +1 -87
- package/dist/server/Plugin.d.ts +4 -0
- package/dist/server/Plugin.js +137 -150
- package/dist/server/actions.js +140 -34
- package/dist/server/forms/create.d.ts +2 -2
- package/dist/server/forms/create.js +3 -3
- package/dist/server/forms/index.d.ts +2 -2
- package/dist/server/forms/update.d.ts +2 -2
- package/dist/server/forms/update.js +4 -4
- package/dist/server/migrations/20260723120000-rebuild-workflow-task-stats.d.ts +13 -0
- package/dist/server/migrations/20260723120000-rebuild-workflow-task-stats.js +51 -0
- package/package.json +2 -2
package/dist/server/Plugin.js
CHANGED
|
@@ -45,18 +45,62 @@ var jobActions = __toESM(require("./actions"));
|
|
|
45
45
|
var import_ManualInstruction = __toESM(require("./ManualInstruction"));
|
|
46
46
|
var import_constants = require("../common/constants");
|
|
47
47
|
class Plugin_default extends import_server.Plugin {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
mergeTaskCounts(statsMap, rows, workflowKeyMap, field) {
|
|
49
|
+
for (const row of rows) {
|
|
50
|
+
const userId = row.userId;
|
|
51
|
+
const workflowKey = workflowKeyMap.get(row.workflowId);
|
|
52
|
+
if (!userId || !workflowKey) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const key = `${userId}\0${workflowKey}`;
|
|
56
|
+
const stats = statsMap.get(key) ?? {
|
|
57
|
+
userId,
|
|
58
|
+
workflowKey,
|
|
59
|
+
type: import_constants.TASK_TYPE_MANUAL,
|
|
60
|
+
pending: 0,
|
|
61
|
+
all: 0
|
|
62
|
+
};
|
|
63
|
+
stats[field] += Number(row.count) || 0;
|
|
64
|
+
statsMap.set(key, stats);
|
|
51
65
|
}
|
|
66
|
+
}
|
|
67
|
+
async collectManualTaskStats(options) {
|
|
68
|
+
var _a, _b;
|
|
52
69
|
const workflowPlugin = this.app.pm.get(import_plugin_workflow.default);
|
|
53
70
|
const WorkflowManualTaskModel = this.db.getModel("workflowManualTasks");
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
71
|
+
const qualifiedColumn = (name) => {
|
|
72
|
+
const fieldName = WorkflowManualTaskModel.getAttributes()[name].field ?? name;
|
|
73
|
+
return this.db.sequelize.col(`${WorkflowManualTaskModel.name}.${fieldName}`);
|
|
74
|
+
};
|
|
75
|
+
const group = ["userId", "workflowId"].map((name) => qualifiedColumn(name));
|
|
76
|
+
const countColumn = qualifiedColumn("id");
|
|
77
|
+
const where = {};
|
|
78
|
+
if ((_a = options.userIds) == null ? void 0 : _a.length) {
|
|
79
|
+
where.userId = options.userIds;
|
|
80
|
+
}
|
|
81
|
+
if ((_b = options.workflowKeys) == null ? void 0 : _b.length) {
|
|
82
|
+
const workflowIds2 = (await Promise.all(
|
|
83
|
+
options.workflowKeys.map(
|
|
84
|
+
(workflowKey) => workflowPlugin.getWorkflowIdsByKey(workflowKey, options.transaction)
|
|
85
|
+
)
|
|
86
|
+
)).flat();
|
|
87
|
+
if (!workflowIds2.length) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
where.workflowId = workflowIds2;
|
|
91
|
+
}
|
|
92
|
+
const allCounts = await WorkflowManualTaskModel.findAll({
|
|
93
|
+
attributes: ["userId", "workflowId", [this.db.sequelize.fn("COUNT", countColumn), "count"]],
|
|
94
|
+
where,
|
|
95
|
+
group,
|
|
96
|
+
raw: true,
|
|
97
|
+
transaction: options.transaction
|
|
98
|
+
});
|
|
99
|
+
const pendingCounts = await WorkflowManualTaskModel.findAll({
|
|
100
|
+
attributes: ["userId", "workflowId", [this.db.sequelize.fn("COUNT", countColumn), "count"]],
|
|
57
101
|
where: {
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
...where,
|
|
103
|
+
status: import_constants.TASK_STATUS.PENDING
|
|
60
104
|
},
|
|
61
105
|
include: [
|
|
62
106
|
{
|
|
@@ -68,58 +112,87 @@ class Plugin_default extends import_server.Plugin {
|
|
|
68
112
|
required: true
|
|
69
113
|
}
|
|
70
114
|
],
|
|
71
|
-
|
|
72
|
-
|
|
115
|
+
group,
|
|
116
|
+
raw: true,
|
|
117
|
+
transaction: options.transaction
|
|
118
|
+
});
|
|
119
|
+
const workflowIds = Array.from(new Set([...allCounts, ...pendingCounts].map((row) => row.workflowId)));
|
|
120
|
+
const workflows = workflowIds.length ? await this.db.getRepository("workflows").find({
|
|
121
|
+
filter: { id: workflowIds },
|
|
122
|
+
fields: ["id", "key"],
|
|
123
|
+
transaction: options.transaction
|
|
124
|
+
}) : [];
|
|
125
|
+
const workflowKeyMap = new Map(
|
|
126
|
+
workflows.map((workflow) => [workflow.id, workflow.key])
|
|
127
|
+
);
|
|
128
|
+
const statsMap = /* @__PURE__ */ new Map();
|
|
129
|
+
this.mergeTaskCounts(statsMap, allCounts, workflowKeyMap, "all");
|
|
130
|
+
this.mergeTaskCounts(statsMap, pendingCounts, workflowKeyMap, "pending");
|
|
131
|
+
return Array.from(statsMap.values());
|
|
132
|
+
}
|
|
133
|
+
async updateManualWorkflowTaskStats(userId, workflowKey, transaction) {
|
|
134
|
+
const workflowPlugin = this.app.pm.get(import_plugin_workflow.default);
|
|
135
|
+
const [row] = await this.collectManualTaskStats({
|
|
136
|
+
userIds: [userId],
|
|
137
|
+
workflowKeys: [workflowKey],
|
|
73
138
|
transaction
|
|
74
139
|
});
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
140
|
+
const stats = row ?? {
|
|
141
|
+
userId,
|
|
142
|
+
workflowKey,
|
|
143
|
+
type: import_constants.TASK_TYPE_MANUAL,
|
|
144
|
+
pending: 0,
|
|
145
|
+
all: 0
|
|
146
|
+
};
|
|
147
|
+
await workflowPlugin.updateTaskStatsByWorkflow(
|
|
148
|
+
{
|
|
149
|
+
userId,
|
|
150
|
+
workflowKey,
|
|
151
|
+
type: import_constants.TASK_TYPE_MANUAL,
|
|
152
|
+
stats
|
|
78
153
|
},
|
|
79
|
-
|
|
80
|
-
|
|
154
|
+
{ transaction }
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
async getWorkflowKeyById(workflowId, transaction) {
|
|
158
|
+
const WorkflowRepo = this.db.getRepository("workflows");
|
|
159
|
+
const workflow = await WorkflowRepo.findOne({
|
|
160
|
+
filterByTk: workflowId,
|
|
161
|
+
fields: ["key"],
|
|
81
162
|
transaction
|
|
82
163
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
164
|
+
return workflow == null ? void 0 : workflow.key;
|
|
165
|
+
}
|
|
166
|
+
async updateManualTaskStats(userIds, transaction) {
|
|
167
|
+
if (!userIds.length) {
|
|
168
|
+
return;
|
|
88
169
|
}
|
|
89
|
-
|
|
90
|
-
|
|
170
|
+
const workflowPlugin = this.app.pm.get(import_plugin_workflow.default);
|
|
171
|
+
const uniqueUserIds = Array.from(new Set(userIds.filter(Boolean)));
|
|
172
|
+
const rows = await this.collectManualTaskStats({ userIds: uniqueUserIds, transaction });
|
|
173
|
+
for (const row of rows) {
|
|
174
|
+
await workflowPlugin.updateTaskStatsByWorkflow(
|
|
175
|
+
{
|
|
176
|
+
userId: row.userId,
|
|
177
|
+
workflowKey: row.workflowKey,
|
|
178
|
+
type: import_constants.TASK_TYPE_MANUAL,
|
|
179
|
+
stats: row
|
|
180
|
+
},
|
|
181
|
+
{ transaction }
|
|
182
|
+
);
|
|
91
183
|
}
|
|
92
184
|
}
|
|
93
185
|
onTaskSave = async (task, { transaction }) => {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
attributes: [],
|
|
105
|
-
where: {
|
|
106
|
-
status: import_plugin_workflow.EXECUTION_STATUS.STARTED
|
|
107
|
-
},
|
|
108
|
-
required: true
|
|
109
|
-
}
|
|
110
|
-
],
|
|
111
|
-
col: "id",
|
|
112
|
-
distinct: true,
|
|
113
|
-
transaction
|
|
114
|
-
});
|
|
115
|
-
const all = await ModelClass.count({
|
|
116
|
-
where: {
|
|
117
|
-
userId: task.userId
|
|
118
|
-
},
|
|
119
|
-
col: "id",
|
|
120
|
-
transaction
|
|
121
|
-
});
|
|
122
|
-
await workflowPlugin.updateTasksStats(task.userId, import_constants.TASK_TYPE_MANUAL, { pending, all }, { transaction });
|
|
186
|
+
const userId = task.get("userId");
|
|
187
|
+
const workflowId = task.get("workflowId");
|
|
188
|
+
if (!userId || !workflowId) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const workflowKey = await this.getWorkflowKeyById(workflowId, transaction);
|
|
192
|
+
if (!workflowKey) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
await this.updateManualWorkflowTaskStats(userId, workflowKey, transaction);
|
|
123
196
|
};
|
|
124
197
|
onExecutionStatusChange = async (execution, { transaction }) => {
|
|
125
198
|
if (!execution.status) {
|
|
@@ -167,105 +240,15 @@ class Plugin_default extends import_server.Plugin {
|
|
|
167
240
|
await this.updateManualTaskStats(userIds, transaction);
|
|
168
241
|
};
|
|
169
242
|
onWorkflowStatusChange = async (workflow, { transaction }) => {
|
|
170
|
-
const workflowPlugin = this.app.pm.get(import_plugin_workflow.default);
|
|
171
243
|
const WorkflowManualTaskModel = this.db.getModel("workflowManualTasks");
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
where: {
|
|
181
|
-
status: import_constants.TASK_STATUS.PENDING,
|
|
182
|
-
workflowId
|
|
183
|
-
},
|
|
184
|
-
include: [
|
|
185
|
-
{
|
|
186
|
-
association: "execution",
|
|
187
|
-
attributes: [],
|
|
188
|
-
where: {
|
|
189
|
-
status: import_plugin_workflow.EXECUTION_STATUS.STARTED
|
|
190
|
-
},
|
|
191
|
-
required: true
|
|
192
|
-
}
|
|
193
|
-
],
|
|
194
|
-
col: "id",
|
|
195
|
-
group: ["userId"],
|
|
196
|
-
transaction
|
|
197
|
-
});
|
|
198
|
-
allCounts = await WorkflowManualTaskModel.count({
|
|
199
|
-
where: {
|
|
200
|
-
workflowId
|
|
201
|
-
},
|
|
202
|
-
col: "id",
|
|
203
|
-
group: ["userId"],
|
|
204
|
-
transaction
|
|
205
|
-
});
|
|
206
|
-
} else {
|
|
207
|
-
enalbedSet.delete(workflow.id);
|
|
208
|
-
const workflowId = [...enalbedSet];
|
|
209
|
-
const tasksByUser = await WorkflowManualTaskModel.count({
|
|
210
|
-
col: "userId",
|
|
211
|
-
where: {
|
|
212
|
-
status: import_constants.TASK_STATUS.PENDING,
|
|
213
|
-
workflowId: workflow.id
|
|
214
|
-
},
|
|
215
|
-
distinct: true,
|
|
216
|
-
group: ["userId"],
|
|
217
|
-
transaction
|
|
218
|
-
});
|
|
219
|
-
const userId = [];
|
|
220
|
-
for (const item of tasksByUser) {
|
|
221
|
-
userId.push(item.userId);
|
|
222
|
-
userStatsMap.set(item.userId, { pending: 0, all: 0 });
|
|
223
|
-
}
|
|
224
|
-
pendingCounts = await WorkflowManualTaskModel.count({
|
|
225
|
-
where: {
|
|
226
|
-
status: import_constants.TASK_STATUS.PENDING,
|
|
227
|
-
userId,
|
|
228
|
-
workflowId
|
|
229
|
-
},
|
|
230
|
-
include: [
|
|
231
|
-
{
|
|
232
|
-
association: "execution",
|
|
233
|
-
attributes: [],
|
|
234
|
-
where: {
|
|
235
|
-
status: import_plugin_workflow.EXECUTION_STATUS.STARTED
|
|
236
|
-
},
|
|
237
|
-
required: true
|
|
238
|
-
}
|
|
239
|
-
],
|
|
240
|
-
col: "id",
|
|
241
|
-
group: ["userId"],
|
|
242
|
-
transaction
|
|
243
|
-
});
|
|
244
|
-
allCounts = await WorkflowManualTaskModel.count({
|
|
245
|
-
where: {
|
|
246
|
-
userId,
|
|
247
|
-
workflowId
|
|
248
|
-
},
|
|
249
|
-
col: "id",
|
|
250
|
-
group: ["userId"],
|
|
251
|
-
transaction
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
for (const row of pendingCounts) {
|
|
255
|
-
if (!userStatsMap.get(row.userId)) {
|
|
256
|
-
userStatsMap.set(row.userId, { pending: 0, all: 0 });
|
|
257
|
-
}
|
|
258
|
-
userStatsMap.set(row.userId, { ...userStatsMap.get(row.userId), pending: Number(row.count) || 0 });
|
|
259
|
-
}
|
|
260
|
-
for (const row of allCounts) {
|
|
261
|
-
if (!userStatsMap.get(row.userId)) {
|
|
262
|
-
userStatsMap.set(row.userId, { pending: 0, all: 0 });
|
|
263
|
-
}
|
|
264
|
-
userStatsMap.set(row.userId, { ...userStatsMap.get(row.userId), all: Number(row.count) || 0 });
|
|
265
|
-
}
|
|
266
|
-
for (const [userId, stats] of userStatsMap.entries()) {
|
|
267
|
-
await workflowPlugin.updateTasksStats(userId, import_constants.TASK_TYPE_MANUAL, stats, { transaction });
|
|
268
|
-
}
|
|
244
|
+
const rows = await WorkflowManualTaskModel.findAll({
|
|
245
|
+
attributes: ["userId"],
|
|
246
|
+
where: {
|
|
247
|
+
workflowId: workflow.id
|
|
248
|
+
},
|
|
249
|
+
transaction
|
|
250
|
+
});
|
|
251
|
+
await this.updateManualTaskStats(rows.map((row) => row.get("userId")).filter(Boolean), transaction);
|
|
269
252
|
};
|
|
270
253
|
async load() {
|
|
271
254
|
this.app.resourceManager.define({
|
|
@@ -275,7 +258,11 @@ class Plugin_default extends import_server.Plugin {
|
|
|
275
258
|
this.app.acl.allow("workflowManualTasks", ["listMine", "get", "submit"], "loggedIn");
|
|
276
259
|
const workflowPlugin = this.app.pm.get(import_plugin_workflow.default);
|
|
277
260
|
workflowPlugin.registerInstruction("manual", import_ManualInstruction.default);
|
|
278
|
-
|
|
261
|
+
workflowPlugin.registerTaskStatsProvider(import_constants.TASK_TYPE_MANUAL, {
|
|
262
|
+
collectTaskStats: (options) => this.collectManualTaskStats(options)
|
|
263
|
+
});
|
|
264
|
+
this.db.on("workflowManualTasks.afterCreateWithAssociations", this.onTaskSave);
|
|
265
|
+
this.db.on("workflowManualTasks.afterUpdate", this.onTaskSave);
|
|
279
266
|
this.db.on("workflowManualTasks.afterDestroy", this.onTaskSave);
|
|
280
267
|
this.db.on("executions.afterUpdate", this.onExecutionStatusChange);
|
|
281
268
|
}
|
package/dist/server/actions.js
CHANGED
|
@@ -41,7 +41,62 @@ __export(actions_exports, {
|
|
|
41
41
|
});
|
|
42
42
|
module.exports = __toCommonJS(actions_exports);
|
|
43
43
|
var import_actions = __toESM(require("@nocobase/actions"));
|
|
44
|
+
var import_database = require("@nocobase/database");
|
|
44
45
|
var import_plugin_workflow = __toESM(require("@nocobase/plugin-workflow"));
|
|
46
|
+
function getSubmittedRatio(tasks) {
|
|
47
|
+
if (!tasks.length) {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
const submitted = tasks.reduce((count, item) => item.status !== import_plugin_workflow.JOB_STATUS.PENDING ? count + 1 : count, 0);
|
|
51
|
+
return submitted / tasks.length;
|
|
52
|
+
}
|
|
53
|
+
function getSingleModeStatus(distribution) {
|
|
54
|
+
var _a;
|
|
55
|
+
return ((_a = distribution.find((item) => item.status !== import_plugin_workflow.JOB_STATUS.PENDING && item.count > 0)) == null ? void 0 : _a.status) ?? null;
|
|
56
|
+
}
|
|
57
|
+
function getAllModeStatus(distribution, assignees) {
|
|
58
|
+
const resolved = distribution.find((item) => item.status === import_plugin_workflow.JOB_STATUS.RESOLVED);
|
|
59
|
+
if ((resolved == null ? void 0 : resolved.count) === assignees.length) {
|
|
60
|
+
return import_plugin_workflow.JOB_STATUS.RESOLVED;
|
|
61
|
+
}
|
|
62
|
+
const rejected = distribution.find((item) => item.status < import_plugin_workflow.JOB_STATUS.PENDING);
|
|
63
|
+
return (rejected == null ? void 0 : rejected.count) ? rejected.status : null;
|
|
64
|
+
}
|
|
65
|
+
function getAnyModeStatus(distribution, assignees) {
|
|
66
|
+
const resolved = distribution.find((item) => item.status === import_plugin_workflow.JOB_STATUS.RESOLVED);
|
|
67
|
+
if (resolved == null ? void 0 : resolved.count) {
|
|
68
|
+
return import_plugin_workflow.JOB_STATUS.RESOLVED;
|
|
69
|
+
}
|
|
70
|
+
const rejectedCount = distribution.reduce(
|
|
71
|
+
(count, item) => item.status < import_plugin_workflow.JOB_STATUS.PENDING ? count + item.count : count,
|
|
72
|
+
0
|
|
73
|
+
);
|
|
74
|
+
return rejectedCount === assignees.length ? import_plugin_workflow.JOB_STATUS.REJECTED : null;
|
|
75
|
+
}
|
|
76
|
+
async function updateJobByManualTasks(job, node, database, latestTask, transaction) {
|
|
77
|
+
const mode = node.config.mode ?? 0;
|
|
78
|
+
const tasks = await database.getModel("workflowManualTasks").findAll({
|
|
79
|
+
where: {
|
|
80
|
+
jobId: job.id
|
|
81
|
+
},
|
|
82
|
+
transaction
|
|
83
|
+
});
|
|
84
|
+
const assignees = [];
|
|
85
|
+
const distributionMap = /* @__PURE__ */ new Map();
|
|
86
|
+
for (const task of tasks) {
|
|
87
|
+
distributionMap.set(task.status, (distributionMap.get(task.status) ?? 0) + 1);
|
|
88
|
+
assignees.push(task.userId);
|
|
89
|
+
}
|
|
90
|
+
const distribution = Array.from(distributionMap.entries()).map(([status2, count]) => ({ status: status2, count }));
|
|
91
|
+
const status = mode === 1 ? getAllModeStatus(distribution, assignees) : mode === -1 ? getAnyModeStatus(distribution, assignees) : getSingleModeStatus(distribution);
|
|
92
|
+
await job.update(
|
|
93
|
+
{
|
|
94
|
+
status: status ?? import_plugin_workflow.JOB_STATUS.PENDING,
|
|
95
|
+
result: mode ? getSubmittedRatio(tasks) : latestTask.result ?? job.result
|
|
96
|
+
},
|
|
97
|
+
{ transaction }
|
|
98
|
+
);
|
|
99
|
+
}
|
|
45
100
|
async function submit(context, next) {
|
|
46
101
|
var _a, _b, _c;
|
|
47
102
|
const repository = import_actions.utils.getRepositoryFromParams(context);
|
|
@@ -78,48 +133,99 @@ async function submit(context, next) {
|
|
|
78
133
|
return context.throw(400);
|
|
79
134
|
}
|
|
80
135
|
task.execution.workflow = task.workflow;
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
136
|
+
const formConfig = forms[formKey];
|
|
137
|
+
const handler = instruction.formTypes.get(formConfig.type);
|
|
138
|
+
const usesMainDataSource = (formConfig.dataSource ?? "main") === "main";
|
|
139
|
+
const transactionOptions = context.db.sequelize.getDialect() === "sqlite" ? { type: import_database.Transaction.TYPES.IMMEDIATE } : {};
|
|
140
|
+
const validateTask = () => {
|
|
141
|
+
if (task.status !== import_plugin_workflow.JOB_STATUS.PENDING || task.job.status !== import_plugin_workflow.JOB_STATUS.PENDING || task.execution.status !== import_plugin_workflow.EXECUTION_STATUS.STARTED) {
|
|
142
|
+
return context.throw(400);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const getPresetValues = (processor) => {
|
|
146
|
+
const assignees = processor.getParsedValue(task.node.config.assignees ?? [], task.nodeId).flat().filter(Boolean);
|
|
147
|
+
if (!assignees.includes(currentUser.id) || task.userId !== currentUser.id) {
|
|
148
|
+
return context.throw(403);
|
|
149
|
+
}
|
|
150
|
+
return processor.getParsedValue(actionItem.values ?? {}, task.nodeId, {
|
|
151
|
+
additionalScope: {
|
|
152
|
+
// @deprecated
|
|
153
|
+
currentUser,
|
|
154
|
+
// @deprecated
|
|
155
|
+
currentRecord: values.result[formKey],
|
|
156
|
+
// @deprecated
|
|
157
|
+
currentTime: /* @__PURE__ */ new Date(),
|
|
158
|
+
$user: currentUser,
|
|
159
|
+
$nForm: values.result[formKey],
|
|
160
|
+
$nDate: {
|
|
161
|
+
now: /* @__PURE__ */ new Date()
|
|
162
|
+
}
|
|
99
163
|
}
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
const setTaskResult = (presetValues) => {
|
|
167
|
+
task.set({
|
|
168
|
+
status: actionItem.status,
|
|
169
|
+
result: actionItem.status ? { [formKey]: { ...values.result[formKey], ...presetValues }, _: actionKey } : { ...task.result ?? {}, ...values.result }
|
|
170
|
+
});
|
|
171
|
+
task.changed("result", true);
|
|
172
|
+
};
|
|
173
|
+
const handleFormSubmission = async (transaction) => {
|
|
174
|
+
const processor = plugin.createProcessor(task.execution, { transaction });
|
|
175
|
+
await processor.prepare();
|
|
176
|
+
const presetValues = getPresetValues(processor);
|
|
177
|
+
setTaskResult(presetValues);
|
|
178
|
+
if (handler && task.status) {
|
|
179
|
+
const { actions: actions2, ...formOptions } = formConfig;
|
|
180
|
+
const parsedFormConfig = {
|
|
181
|
+
...processor.getParsedValue(formOptions, task.nodeId),
|
|
182
|
+
actions: actions2
|
|
183
|
+
};
|
|
184
|
+
await handler.call(instruction, task, parsedFormConfig, transaction);
|
|
100
185
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
186
|
+
return presetValues;
|
|
187
|
+
};
|
|
188
|
+
let shouldResume = false;
|
|
189
|
+
try {
|
|
190
|
+
const lock = await context.app.lockManager.tryAcquire((0, import_plugin_workflow.getJobLockKey)(task.job.id));
|
|
191
|
+
await lock.runExclusive(async () => {
|
|
192
|
+
let presetValues = {};
|
|
193
|
+
if (!usesMainDataSource) {
|
|
194
|
+
await Promise.all([task.reload(), task.job.reload(), task.execution.reload()]);
|
|
195
|
+
validateTask();
|
|
196
|
+
presetValues = await handleFormSubmission();
|
|
197
|
+
}
|
|
198
|
+
await context.db.sequelize.transaction(transactionOptions, async (transaction) => {
|
|
199
|
+
await Promise.all([
|
|
200
|
+
task.reload({ transaction }),
|
|
201
|
+
task.job.reload({ transaction }),
|
|
202
|
+
task.execution.reload({ transaction })
|
|
203
|
+
]);
|
|
204
|
+
validateTask();
|
|
205
|
+
if (usesMainDataSource) {
|
|
206
|
+
await handleFormSubmission(transaction);
|
|
207
|
+
} else {
|
|
208
|
+
setTaskResult(presetValues);
|
|
209
|
+
}
|
|
210
|
+
await task.save({ transaction });
|
|
211
|
+
await updateJobByManualTasks(task.job, task.node, context.db, task, transaction);
|
|
212
|
+
shouldResume = task.job.status !== import_plugin_workflow.JOB_STATUS.PENDING;
|
|
213
|
+
});
|
|
214
|
+
}, 6e4);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
if ((0, import_plugin_workflow.isLockAcquireError)(error)) {
|
|
217
|
+
return context.throw(409);
|
|
218
|
+
}
|
|
219
|
+
throw error;
|
|
110
220
|
}
|
|
111
|
-
await task.save();
|
|
112
|
-
await processor.exit();
|
|
113
221
|
context.body = task;
|
|
114
222
|
context.status = 202;
|
|
115
223
|
await next();
|
|
116
|
-
if (
|
|
224
|
+
if (!shouldResume) {
|
|
117
225
|
return;
|
|
118
226
|
}
|
|
119
|
-
task.
|
|
120
|
-
task.job.
|
|
121
|
-
processor.logger.info(`manual node (${task.nodeId}) action trigger execution (${task.execution.id}) to resume`);
|
|
122
|
-
plugin.resume(task.job);
|
|
227
|
+
plugin.getLogger(task.execution.workflowId).info(`manual node (${task.nodeId}) action trigger execution (${task.execution.id}) to resume`);
|
|
228
|
+
plugin.resume(task.job).catch(() => void 0);
|
|
123
229
|
}
|
|
124
230
|
async function listMine(context, next) {
|
|
125
231
|
context.action.mergeParams({
|
|
@@ -6,9 +6,9 @@
|
|
|
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 {
|
|
9
|
+
import type { Transaction } from '@nocobase/database';
|
|
10
10
|
import ManualInstruction from '../ManualInstruction';
|
|
11
11
|
export default function (this: ManualInstruction, instance: any, { dataSource, collection }: {
|
|
12
12
|
dataSource?: string;
|
|
13
13
|
collection: any;
|
|
14
|
-
},
|
|
14
|
+
}, transaction?: Transaction): Promise<void>;
|
|
@@ -29,7 +29,7 @@ __export(create_exports, {
|
|
|
29
29
|
default: () => create_default
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(create_exports);
|
|
32
|
-
async function create_default(instance, { dataSource = "main", collection },
|
|
32
|
+
async function create_default(instance, { dataSource = "main", collection }, transaction) {
|
|
33
33
|
const repo = this.workflow.app.dataSourceManager.dataSources.get(dataSource).collectionManager.getRepository(collection);
|
|
34
34
|
if (!repo) {
|
|
35
35
|
throw new Error(`collection ${collection} for create data on manual node not found`);
|
|
@@ -43,8 +43,8 @@ async function create_default(instance, { dataSource = "main", collection }, pro
|
|
|
43
43
|
updatedBy: instance.userId
|
|
44
44
|
},
|
|
45
45
|
context: {
|
|
46
|
-
executionId:
|
|
46
|
+
executionId: instance.executionId
|
|
47
47
|
},
|
|
48
|
-
transaction
|
|
48
|
+
transaction
|
|
49
49
|
});
|
|
50
50
|
}
|
|
@@ -6,9 +6,9 @@
|
|
|
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 {
|
|
9
|
+
import type { Transaction } from '@nocobase/database';
|
|
10
10
|
import ManualInstruction from '../ManualInstruction';
|
|
11
|
-
export type FormHandler = (this: ManualInstruction, instance: any, formConfig: any,
|
|
11
|
+
export type FormHandler = (this: ManualInstruction, instance: any, formConfig: any, transaction?: Transaction) => Promise<void>;
|
|
12
12
|
export default function ({ formTypes }: {
|
|
13
13
|
formTypes: any;
|
|
14
14
|
}): void;
|
|
@@ -6,10 +6,10 @@
|
|
|
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 {
|
|
9
|
+
import type { Transaction } from '@nocobase/database';
|
|
10
10
|
import ManualInstruction from '../ManualInstruction';
|
|
11
11
|
export default function (this: ManualInstruction, instance: any, { dataSource, collection, filter }: {
|
|
12
12
|
dataSource?: string;
|
|
13
13
|
collection: any;
|
|
14
14
|
filter?: {};
|
|
15
|
-
},
|
|
15
|
+
}, transaction?: Transaction): Promise<void>;
|
|
@@ -29,7 +29,7 @@ __export(update_exports, {
|
|
|
29
29
|
default: () => update_default
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(update_exports);
|
|
32
|
-
async function update_default(instance, { dataSource = "main", collection, filter = {} },
|
|
32
|
+
async function update_default(instance, { dataSource = "main", collection, filter = {} }, transaction) {
|
|
33
33
|
const repo = this.workflow.app.dataSourceManager.dataSources.get(dataSource).collectionManager.getRepository(collection);
|
|
34
34
|
if (!repo) {
|
|
35
35
|
throw new Error(`collection ${collection} for update data on manual node not found`);
|
|
@@ -37,14 +37,14 @@ async function update_default(instance, { dataSource = "main", collection, filte
|
|
|
37
37
|
const { _, ...form } = instance.result;
|
|
38
38
|
const [values] = Object.values(form);
|
|
39
39
|
await repo.update({
|
|
40
|
-
filter
|
|
40
|
+
filter,
|
|
41
41
|
values: {
|
|
42
42
|
...values ?? {},
|
|
43
43
|
updatedBy: instance.userId
|
|
44
44
|
},
|
|
45
45
|
context: {
|
|
46
|
-
executionId:
|
|
46
|
+
executionId: instance.executionId
|
|
47
47
|
},
|
|
48
|
-
transaction
|
|
48
|
+
transaction
|
|
49
49
|
});
|
|
50
50
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
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 { Migration } from '@nocobase/server';
|
|
10
|
+
export default class extends Migration {
|
|
11
|
+
on: string;
|
|
12
|
+
up(): Promise<void>;
|
|
13
|
+
}
|