fix(workflow): 添加提交按钮允许绑定通用工作流并触发 (#1560)

Reviewed-on: daoyoucloud/tachybase#1560
Reviewed-by: sealday <zhanglin@daoyoucloud.com>
Co-authored-by: bai.zixv <bai.zixv@foxmail.com>
Co-committed-by: bai.zixv <bai.zixv@foxmail.com>
This commit is contained in:
bai.zixv 2024-09-24 15:02:19 +08:00 committed by sealday
parent eff5bc3890
commit 569dbf2423
2 changed files with 143 additions and 16 deletions

View File

@ -55,8 +55,11 @@ export class OmniActionTrigger extends Trigger {
}; };
scope = { useCollectionDataSource }; scope = { useCollectionDataSource };
components = {}; components = {};
isActionTriggerable = (config, context) => { isActionTriggerable = (config, context: any = {}) => {
return context.buttonAction === 'customize:triggerWorkflows'; const { buttonAction } = context;
const conditionList = [buttonAction === 'customize:triggerWorkflows', buttonAction === 'submit'];
const isAvailable = conditionList.some((val) => val === true);
return isAvailable;
}; };
useVariables(config: Record<string, any>, options?: UseVariableOptions) { useVariables(config: Record<string, any>, options?: UseVariableOptions) {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks

View File

@ -1,7 +1,9 @@
import { Context, Next } from '@tachybase/actions';
import { joinCollectionName, parseCollectionName } from '@tachybase/data-source-manager'; import { joinCollectionName, parseCollectionName } from '@tachybase/data-source-manager';
import { Model, modelAssociationByKey } from '@tachybase/database';
import PluginErrorHandler from '@tachybase/plugin-error-handler'; import PluginErrorHandler from '@tachybase/plugin-error-handler';
import _, { isArray } from 'lodash'; import _, { get, isArray } from 'lodash';
import { EXECUTION_STATUS } from '../../constants'; import { EXECUTION_STATUS } from '../../constants';
import Trigger from '../../triggers'; import Trigger from '../../triggers';
@ -17,6 +19,21 @@ class CustomActionInterceptionError extends Error {
} }
export class OmniTrigger extends Trigger { export class OmniTrigger extends Trigger {
static TYPE = 'general-action'; static TYPE = 'general-action';
constructor(workflow) {
super(workflow);
this.workflow.app.resourcer.registerActionHandler('trigger', this.triggerAction);
this.workflow.app.acl.allow('*', 'trigger', 'loggedIn');
(this.workflow.app.pm.get(PluginErrorHandler) as PluginErrorHandler).errorHandler.register(
(err) => err instanceof CustomActionInterceptionError,
async (err, ctx) => {
ctx.body = {
errors: err.messages,
};
ctx.status = err.status;
},
);
workflow.app.use(this.middleware, { after: 'dataSource' });
}
triggerAction = async (context, next) => { triggerAction = async (context, next) => {
const { const {
params: { filterByTk, values, triggerWorkflows = '', filter, resourceName, actionName }, params: { filterByTk, values, triggerWorkflows = '', filter, resourceName, actionName },
@ -123,20 +140,127 @@ export class OmniTrigger extends Trigger {
} }
await next(); await next();
}; };
constructor(workflow) {
super(workflow); middleware = async (context: Context, next: Next) => {
this.workflow.app.resourcer.registerActionHandler('trigger', this.triggerAction); const {
this.workflow.app.acl.allow('*', 'trigger', 'loggedIn'); resourceName,
(this.workflow.app.pm.get(PluginErrorHandler) as PluginErrorHandler).errorHandler.register( actionName,
(err) => err instanceof CustomActionInterceptionError, params: { triggerWorkflows },
async (err, ctx) => { } = context.action;
ctx.body = {
errors: err.messages, if (resourceName === 'workflows' && actionName === 'trigger') {
}; return this.triggerAction(context, next);
ctx.status = err.status;
},
);
} }
await next();
if (!triggerWorkflows) {
return;
}
if (!['create', 'update'].includes(actionName)) {
return;
}
return this.trigger(context);
};
private async trigger(context: Context) {
const { triggerWorkflows = '', values } = context.action.params;
const dataSourceHeader = context.get('x-data-source') || 'main';
const { currentUser, currentRole } = context.state;
const { model: UserModel } = this.workflow.db.getCollection('users');
const userInfo = {
user: UserModel.build(currentUser).desensitize(),
roleName: currentRole,
};
const triggers = triggerWorkflows.split(',').map((trigger) => trigger.split('!'));
const workflowRepo = this.workflow.db.getRepository('workflows');
const workflows = (
await workflowRepo.find({
filter: {
key: triggers.map((trigger) => trigger[0]),
current: true,
type: 'general-action',
enabled: true,
},
})
).filter((workflow) => Boolean(workflow.config.collection));
const syncGroup = [];
const asyncGroup = [];
for (const workflow of workflows) {
const { collection, appends = [] } = workflow.config;
const [dataSourceName, collectionName] = parseCollectionName(collection);
const trigger = triggers.find((trigger) => trigger[0] == workflow.key);
const event = [workflow];
if (context.action.resourceName !== 'workflows') {
if (!context.body) {
continue;
}
if (dataSourceName !== dataSourceHeader) {
continue;
}
const { body: data } = context;
for (const row of Array.isArray(data) ? data : [data]) {
let payload = row;
if (trigger[1]) {
const paths = trigger[1].split('.');
for (const field of paths) {
if (payload.get(field)) {
payload = payload.get(field);
} else {
const association: any = modelAssociationByKey(payload, field);
payload = await payload[association.accessors.get]();
}
}
}
const model = payload.constructor;
if (payload instanceof Model) {
if (collectionName !== model.collection.name) {
continue;
}
if (appends.length) {
payload = await model.collection.repository.findOne({
filterByTk: payload.get(model.primaryKeyAttribute),
appends,
});
}
}
// this.workflow.trigger(workflow, { data: toJSON(payload), ...userInfo });
event.push({ data: toJSON(payload), ...userInfo });
}
} else {
const { model, repository } = (<any>context.app).dataSourceManager.dataSources
.get(dataSourceName)
.collectionManager.getCollection(collectionName);
let data = trigger[1] ? get(values, trigger[1]) : values;
const pk = get(data, model.primaryKeyAttribute);
if (appends.length && pk != null) {
data = await repository.findOne({
filterByTk: pk,
appends,
});
}
// this.workflow.trigger(workflow, {
// data,
// ...userInfo,
// });
event.push({ data, ...userInfo });
}
(workflow.sync ? syncGroup : asyncGroup).push(event);
}
for (const event of syncGroup) {
await this.workflow.trigger(event[0], event[1], { httpContext: context });
}
for (const event of asyncGroup) {
this.workflow.trigger(event[0], event[1]);
}
}
on() {} on() {}
off() {} off() {}
} }