mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-01 18:52:20 +08:00
feat(plugin-workflow-action-trigger): add global action events (#3883)
* feat(plugin-workflow-action-trigger): add global action events * feat(plugin-workflow): refine trigger select component style * fix(plugin-workflow-action-trigger): fix unexpected triggering on any action * fix(plugin-workflow-action-trigger): fix global check logic * fix(plugin-workflow): adjust workflow type select style * refactor(plugin-workflow): adjust triggers description * fix(plugin-workflow): adjust events descriptions * fix(plugin-workflow): fix locale * fix(plugin-workflow-action-trigger): fix workflow filter rule in binding configuration * fix(plugin-workflow-action-trigger): fix locale * fix(plugin-workflow-action-trigger): fix locale * fix(plugin-workflow-action-trigger): fix binding filter condition * fix(plugin-workflow-action-trigger): fix locale * fix: trigger type locator --------- Co-authored-by: chenos <chenlinxh@gmail.com> Co-authored-by: hongboji <j414562100@qq.com>
This commit is contained in:
parent
d23f3a3999
commit
0544b8df45
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@nocobase/plugin-workflow-action-trigger",
|
||||
"displayName": "Workflow: Action trigger",
|
||||
"displayName.zh-CN": "工作流:数据操作触发器",
|
||||
"description": "Bind action buttons to trigger workflow events when clicked.",
|
||||
"description.zh-CN": "可对数据操作按钮绑定,在点击后触发对应的工作流事件。",
|
||||
"displayName": "Workflow: Post-action event",
|
||||
"displayName.zh-CN": "工作流:操作后事件",
|
||||
"description": "Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or \"submit to workflow\". Suitable for data processing, sending notifications, etc., after actions are completed.",
|
||||
"description.zh-CN": "通过操作按钮或 API 发起请求并在执行完成后触发,比如新增、更新、删除数据或者“提交至工作流”之后。适用于在操作完成后进行数据处理、发送通知等。",
|
||||
"version": "0.21.0-alpha.1",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/server/index.js",
|
||||
|
@ -11,21 +11,32 @@ import {
|
||||
CollectionBlockInitializer,
|
||||
getCollectionFieldOptions,
|
||||
useWorkflowAnyExecuted,
|
||||
CheckboxGroupWithTooltip,
|
||||
RadioWithTooltip,
|
||||
} from '@nocobase/plugin-workflow/client';
|
||||
import { NAMESPACE, useLang } from '../locale';
|
||||
|
||||
const COLLECTION_TRIGGER_ACTION = {
|
||||
CREATE: 'create',
|
||||
UPDATE: 'update',
|
||||
UPSERT: 'updateOrCreate',
|
||||
DESTROY: 'destroy',
|
||||
};
|
||||
|
||||
export default class extends Trigger {
|
||||
title = `{{t("Action event", { ns: "${NAMESPACE}" })}}`;
|
||||
description = `{{t("Triggers after specific operations on data are submitted, such as create, update, delete, etc., or directly submitting a record to the workflow.", { ns: "${NAMESPACE}" })}}`;
|
||||
title = `{{t("Post-action event", { ns: "${NAMESPACE}" })}}`;
|
||||
description = `{{t('Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or "submit to workflow". Suitable for data processing, sending notifications, etc., after actions are completed.', { ns: "${NAMESPACE}" })}}`;
|
||||
fieldset = {
|
||||
collection: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-decorator-props': {
|
||||
tooltip: `{{t("The collection to which the triggered data belongs.", { ns: "${NAMESPACE}" })}}`,
|
||||
},
|
||||
'x-component': 'DataSourceCollectionCascader',
|
||||
'x-disabled': '{{ useWorkflowAnyExecuted() }}',
|
||||
title: `{{t("Collection", { ns: "${NAMESPACE}" })}}`,
|
||||
description: `{{t("Which collection record belongs to.", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-reactions': [
|
||||
{
|
||||
target: 'appends',
|
||||
@ -38,6 +49,65 @@ export default class extends Trigger {
|
||||
},
|
||||
],
|
||||
},
|
||||
global: {
|
||||
type: 'boolean',
|
||||
title: `{{t("Trigger mode", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'RadioWithTooltip',
|
||||
'x-component-props': {
|
||||
direction: 'vertical',
|
||||
options: [
|
||||
{
|
||||
label: `{{t("Local mode, triggered after the completion of actions bound to this workflow", { ns: "${NAMESPACE}" })}}`,
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
label: `{{t("Global mode, triggered after the completion of the following actions", { ns: "${NAMESPACE}" })}}`,
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
default: false,
|
||||
'x-reactions': [
|
||||
{
|
||||
dependencies: ['collection'],
|
||||
fulfill: {
|
||||
state: {
|
||||
visible: '{{!!$deps[0]}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
actions: {
|
||||
type: 'number',
|
||||
title: `{{t("Select actions", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'CheckboxGroupWithTooltip',
|
||||
'x-component-props': {
|
||||
direction: 'vertical',
|
||||
options: [
|
||||
{ label: `{{t("Create record action", { ns: "${NAMESPACE}" })}}`, value: COLLECTION_TRIGGER_ACTION.CREATE },
|
||||
{ label: `{{t("Update record action", { ns: "${NAMESPACE}" })}}`, value: COLLECTION_TRIGGER_ACTION.UPDATE },
|
||||
// { label: `{{t("upsert", { ns: "${NAMESPACE}" })}}`, value: COLLECTION_TRIGGER_ACTION.UPSERT },
|
||||
// {
|
||||
// label: `{{t("Delete single or many records", { ns: "${NAMESPACE}" })}}`,
|
||||
// value: COLLECTION_TRIGGER_ACTION.DESTROY,
|
||||
// },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
'x-reactions': [
|
||||
{
|
||||
dependencies: ['collection', 'global'],
|
||||
fulfill: {
|
||||
state: {
|
||||
visible: '{{!!$deps[0] && !!$deps[1]}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
appends: {
|
||||
type: 'array',
|
||||
title: `{{t("Associations to use", { ns: "${NAMESPACE}" })}}`,
|
||||
@ -68,8 +138,15 @@ export default class extends Trigger {
|
||||
useCollectionDataSource,
|
||||
useWorkflowAnyExecuted,
|
||||
};
|
||||
components = {
|
||||
RadioWithTooltip,
|
||||
CheckboxGroupWithTooltip,
|
||||
};
|
||||
isActionTriggerable = (config, context) => {
|
||||
return ['create', 'update', 'customize:update', 'customize:triggerWorkflows'].includes(context.action);
|
||||
return (
|
||||
context.action === 'customize:triggerWorkflows' ||
|
||||
(['create', 'update', 'customize:update'].includes(context.action) && !config.global)
|
||||
);
|
||||
};
|
||||
useVariables(config, options) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
|
@ -56,7 +56,7 @@ test.describe('Add new', () => {
|
||||
const workFlowName = faker.string.alphanumeric(5);
|
||||
await createWorkFlow.name.fill(workFlowName);
|
||||
await createWorkFlow.triggerType.click();
|
||||
await page.getByRole('option', { name: 'Action event' }).click();
|
||||
await page.getByTitle('Post-action event').click();
|
||||
await page.getByLabel('action-Action-Submit-workflows').click();
|
||||
|
||||
// 3、预期结果:列表中出现新建的工作流
|
||||
|
@ -1,8 +1,16 @@
|
||||
{
|
||||
"Action event": "操作事件",
|
||||
"Triggers after specific operations on data are submitted, such as create, update, delete, etc., or directly submitting a record to the workflow.": "在对数据的特定操作提交后触发,如创建、更新、删除等,或直接提交一条数据至工作流。",
|
||||
"Post-action event": "操作后事件",
|
||||
"Triggered after the completion of a request initiated through an action button or API, such as after adding, updating, deleting data, or \"submit to workflow\". Suitable for data processing, sending notifications, etc., after actions are completed.":
|
||||
"通过操作按钮或 API 发起请求并在执行完成后触发,比如新增、更新、删除数据或者“提交至工作流”之后。适用于在操作完成后进行数据处理、发送通知等。",
|
||||
"Collection": "数据表",
|
||||
"Which collection record belongs to.": "数据所属的数据表。",
|
||||
"The collection to which the triggered data belongs.": "触发数据所属的数据表。",
|
||||
"Trigger mode": "触发模式",
|
||||
"Local mode, triggered after the completion of actions bound to this workflow": "局部模式,绑定该工作流的操作执行完成后触发",
|
||||
"Global mode, triggered after the completion of the following actions": "全局模式,以下操作执行完成后都触发",
|
||||
"Action to submit to workflow directly is only supported on bound buttons, and will not be affected under global mode.": "直接提交至工作流的操作仅支持使用按钮绑定,不受全局模式的影响。",
|
||||
"Select actions": "选择操作",
|
||||
"Create record action": "创建记录操作",
|
||||
"Update record action": "更新记录操作",
|
||||
"Associations to use": "待使用的关系数据",
|
||||
"Trigger data": "触发器数据",
|
||||
"User submitted action": "提交操作的用户",
|
||||
|
@ -5,18 +5,20 @@ import Application, { DefaultContext } from '@nocobase/server';
|
||||
import { Context as ActionContext, Next } from '@nocobase/actions';
|
||||
|
||||
import WorkflowPlugin, { Trigger, WorkflowModel, toJSON } from '@nocobase/plugin-workflow';
|
||||
import { parseCollectionName } from '@nocobase/data-source-manager';
|
||||
import { joinCollectionName, parseCollectionName } from '@nocobase/data-source-manager';
|
||||
|
||||
interface Context extends ActionContext, DefaultContext {}
|
||||
|
||||
export default class extends Trigger {
|
||||
static TYPE = 'action';
|
||||
|
||||
constructor(workflow: WorkflowPlugin) {
|
||||
super(workflow);
|
||||
|
||||
workflow.app.use(this.middleware, { after: 'dataSource' });
|
||||
}
|
||||
|
||||
async triggerAction(context: Context, next: Next) {
|
||||
async workflowTriggerAction(context: Context, next: Next) {
|
||||
const { triggerWorkflows } = context.action.params;
|
||||
|
||||
if (!triggerWorkflows) {
|
||||
@ -26,37 +28,33 @@ export default class extends Trigger {
|
||||
context.status = 202;
|
||||
await next();
|
||||
|
||||
this.trigger(context);
|
||||
return this.collectionTriggerAction(context);
|
||||
}
|
||||
|
||||
middleware = async (context: Context, next: Next) => {
|
||||
const {
|
||||
resourceName,
|
||||
actionName,
|
||||
params: { triggerWorkflows },
|
||||
} = context.action;
|
||||
const { resourceName, actionName } = context.action;
|
||||
|
||||
if (resourceName === 'workflows' && actionName === 'trigger') {
|
||||
return this.triggerAction(context, next);
|
||||
return this.workflowTriggerAction(context, next);
|
||||
}
|
||||
|
||||
await next();
|
||||
|
||||
if (!triggerWorkflows) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!['create', 'update'].includes(actionName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.trigger(context);
|
||||
return this.collectionTriggerAction(context);
|
||||
};
|
||||
|
||||
private async trigger(context: Context) {
|
||||
const { triggerWorkflows = '', values } = context.action.params;
|
||||
private async collectionTriggerAction(context: Context) {
|
||||
const {
|
||||
resourceName,
|
||||
actionName,
|
||||
params: { triggerWorkflows = '', values },
|
||||
} = context.action;
|
||||
const dataSourceHeader = context.get('x-data-source') || 'main';
|
||||
|
||||
const fullCollectionName = joinCollectionName(dataSourceHeader, resourceName);
|
||||
const { currentUser, currentRole } = context.state;
|
||||
const { model: UserModel } = this.workflow.db.getCollection('users');
|
||||
const userInfo = {
|
||||
@ -65,23 +63,41 @@ export default class extends Trigger {
|
||||
};
|
||||
|
||||
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: 'action',
|
||||
enabled: true,
|
||||
},
|
||||
})
|
||||
).filter((workflow) => Boolean(workflow.config.collection));
|
||||
const triggersKeysMap = new Map<string, string>(triggers);
|
||||
const workflows = Array.from(this.workflow.enabledCache.values()).filter(
|
||||
(item) => item.type === 'action' && item.config.collection,
|
||||
);
|
||||
const globalWorkflows = new Map();
|
||||
const localWorkflows = new Map();
|
||||
workflows.forEach((item) => {
|
||||
if (resourceName === 'workflows' && actionName === 'trigger') {
|
||||
localWorkflows.set(item.key, item);
|
||||
} else if (item.config.collection === fullCollectionName) {
|
||||
if (item.config.global) {
|
||||
if (item.config.actions?.includes(actionName)) {
|
||||
globalWorkflows.set(item.key, item);
|
||||
}
|
||||
} else {
|
||||
localWorkflows.set(item.key, item);
|
||||
}
|
||||
}
|
||||
});
|
||||
const triggeringLocalWorkflows = [];
|
||||
const uniqueTriggersMap = new Map();
|
||||
triggers.forEach((trigger) => {
|
||||
const [key] = trigger;
|
||||
const workflow = localWorkflows.get(key);
|
||||
if (workflow && !uniqueTriggersMap.has(key)) {
|
||||
triggeringLocalWorkflows.push(workflow);
|
||||
uniqueTriggersMap.set(key, true);
|
||||
}
|
||||
});
|
||||
const syncGroup = [];
|
||||
const asyncGroup = [];
|
||||
for (const workflow of workflows) {
|
||||
for (const workflow of triggeringLocalWorkflows.concat(...globalWorkflows.values())) {
|
||||
const { collection, appends = [] } = workflow.config;
|
||||
const [dataSourceName, collectionName] = parseCollectionName(collection);
|
||||
const trigger = triggers.find((trigger) => trigger[0] == workflow.key);
|
||||
const dataPath = triggersKeysMap.get(workflow.key);
|
||||
const event = [workflow];
|
||||
if (context.action.resourceName !== 'workflows') {
|
||||
if (!context.body) {
|
||||
@ -93,9 +109,12 @@ export default class extends Trigger {
|
||||
const { body: data } = context;
|
||||
for (const row of Array.isArray(data) ? data : [data]) {
|
||||
let payload = row;
|
||||
if (trigger[1]) {
|
||||
const paths = trigger[1].split('.');
|
||||
if (dataPath) {
|
||||
const paths = dataPath.split('.');
|
||||
for (const field of paths) {
|
||||
if (!payload) {
|
||||
break;
|
||||
}
|
||||
if (payload.get(field)) {
|
||||
payload = payload.get(field);
|
||||
} else {
|
||||
@ -104,37 +123,32 @@ export default class extends Trigger {
|
||||
}
|
||||
}
|
||||
}
|
||||
const model = payload.constructor;
|
||||
if (payload instanceof Model) {
|
||||
const model = payload.constructor as unknown as Model;
|
||||
if (collectionName !== model.collection.name) {
|
||||
continue;
|
||||
}
|
||||
if (appends.length) {
|
||||
payload = await model.collection.repository.findOne({
|
||||
filterByTk: payload.get(model.primaryKeyAttribute),
|
||||
filterByTk: payload.get(model.collection.filterTargetKey),
|
||||
appends,
|
||||
});
|
||||
}
|
||||
}
|
||||
// this.workflow.trigger(workflow, { data: toJSON(payload), ...userInfo });
|
||||
event.push({ data: toJSON(payload), ...userInfo });
|
||||
}
|
||||
} else {
|
||||
const { model, repository } = (<Application>context.app).dataSourceManager.dataSources
|
||||
const { filterTargetKey, repository } = (<Application>context.app).dataSourceManager.dataSources
|
||||
.get(dataSourceName)
|
||||
.collectionManager.getCollection(collectionName);
|
||||
let data = trigger[1] ? get(values, trigger[1]) : values;
|
||||
const pk = get(data, model.primaryKeyAttribute);
|
||||
let data = dataPath ? get(values, dataPath) : values;
|
||||
const pk = get(data, filterTargetKey);
|
||||
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);
|
||||
|
@ -572,6 +572,126 @@ describe('workflow > action-trigger', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('global workflow', () => {
|
||||
it('no action configured should not be triggered', async () => {
|
||||
const workflow = await WorkflowModel.create({
|
||||
enabled: true,
|
||||
type: 'action',
|
||||
config: {
|
||||
collection: 'posts',
|
||||
global: true,
|
||||
},
|
||||
});
|
||||
|
||||
const res1 = await userAgents[0].resource('posts').create({
|
||||
values: { title: 't1' },
|
||||
});
|
||||
expect(res1.status).toBe(200);
|
||||
|
||||
await sleep(500);
|
||||
|
||||
const e1 = await workflow.getExecutions();
|
||||
expect(e1.length).toBe(0);
|
||||
|
||||
const res2 = await userAgents[0].resource('posts').create({
|
||||
values: { title: 't1' },
|
||||
triggerWorkflows: `${workflow.key}`,
|
||||
});
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
await sleep(500);
|
||||
|
||||
const e2 = await workflow.getExecutions();
|
||||
expect(e2.length).toBe(0);
|
||||
});
|
||||
|
||||
it('trigger on both create and update actions', async () => {
|
||||
const workflow = await WorkflowModel.create({
|
||||
enabled: true,
|
||||
type: 'action',
|
||||
config: {
|
||||
collection: 'posts',
|
||||
global: true,
|
||||
actions: ['create', 'update'],
|
||||
},
|
||||
});
|
||||
|
||||
const res1 = await userAgents[0].resource('posts').create({
|
||||
values: { title: 't1' },
|
||||
});
|
||||
expect(res1.status).toBe(200);
|
||||
|
||||
await sleep(500);
|
||||
|
||||
const e1 = await workflow.getExecutions();
|
||||
expect(e1.length).toBe(1);
|
||||
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
||||
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
||||
|
||||
const res2 = await userAgents[0].resource('posts').update({
|
||||
filterByTk: res1.body.data.id,
|
||||
values: { title: 't2' },
|
||||
});
|
||||
|
||||
await sleep(500);
|
||||
|
||||
const e2 = await workflow.getExecutions({ order: [['id', 'ASC']] });
|
||||
expect(e2.length).toBe(2);
|
||||
expect(e2[1].status).toBe(EXECUTION_STATUS.RESOLVED);
|
||||
expect(e2[1].context.data).toMatchObject({ title: 't2' });
|
||||
});
|
||||
|
||||
it('trigger on action when bound to button', async () => {
|
||||
const workflow = await WorkflowModel.create({
|
||||
enabled: true,
|
||||
type: 'action',
|
||||
config: {
|
||||
collection: 'posts',
|
||||
global: true,
|
||||
actions: ['create', 'update'],
|
||||
},
|
||||
});
|
||||
|
||||
const res1 = await userAgents[0].resource('posts').create({
|
||||
values: { title: 't1' },
|
||||
triggerWorkflows: `${workflow.key}`,
|
||||
});
|
||||
expect(res1.status).toBe(200);
|
||||
|
||||
await sleep(500);
|
||||
|
||||
const e1 = await workflow.getExecutions();
|
||||
expect(e1.length).toBe(1);
|
||||
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
||||
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
||||
});
|
||||
|
||||
it('trigger on action directly submit to workflow', async () => {
|
||||
const workflow = await WorkflowModel.create({
|
||||
enabled: true,
|
||||
type: 'action',
|
||||
config: {
|
||||
collection: 'posts',
|
||||
global: true,
|
||||
actions: ['create', 'update'],
|
||||
},
|
||||
});
|
||||
|
||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
||||
values: { title: 't1' },
|
||||
triggerWorkflows: `${workflow.key}`,
|
||||
});
|
||||
expect(res1.status).toBe(202);
|
||||
|
||||
await sleep(500);
|
||||
|
||||
const e1 = await workflow.getExecutions();
|
||||
expect(e1.length).toBe(1);
|
||||
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
||||
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple data source', () => {
|
||||
it('trigger on different data source', async () => {
|
||||
const workflow = await WorkflowModel.create({
|
||||
|
@ -43,7 +43,7 @@ test.describe('Add new', () => {
|
||||
const workFlowName = faker.string.alphanumeric(5);
|
||||
await createWorkFlow.name.fill(workFlowName);
|
||||
await createWorkFlow.triggerType.click();
|
||||
await page.getByRole('option', { name: 'Schedule event' }).click();
|
||||
await page.getByTitle('Schedule event').click();
|
||||
await page.getByLabel('action-Action-Submit-workflows').click();
|
||||
|
||||
// 3、预期结果:列表中出现新建的工作流
|
||||
|
@ -55,7 +55,7 @@ test.describe('Add new', () => {
|
||||
const workFlowName = faker.string.alphanumeric(5);
|
||||
await createWorkFlow.name.fill(workFlowName);
|
||||
await createWorkFlow.triggerType.click();
|
||||
await page.getByRole('option', { name: 'Collection event' }).click();
|
||||
await page.getByTitle('Collection event').click();
|
||||
await page.getByLabel('action-Action-Submit-workflows').click();
|
||||
|
||||
// 3、预期结果:列表中出现新建的工作流
|
||||
|
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { Space, Tag, Typography } from 'antd';
|
||||
|
||||
import { useCompile } from '@nocobase/client';
|
||||
|
||||
export function TriggerOptionRender({ data }) {
|
||||
const { label, color, options } = data;
|
||||
const compile = useCompile();
|
||||
return (
|
||||
<Space direction="vertical">
|
||||
<Tag color={color}>{compile(label)}</Tag>
|
||||
<Typography.Text type="secondary" style={{ whiteSpace: 'normal' }}>
|
||||
{compile(options.description)}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
);
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
import { ISchema, useForm } from '@formily/react';
|
||||
import { useActionContext, useRecord, useResourceActionContext, useResourceContext } from '@nocobase/client';
|
||||
import { message } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { NAMESPACE } from '../locale';
|
||||
// import { triggers } from '../triggers';
|
||||
import React from 'react';
|
||||
import { executionSchema } from './executions';
|
||||
import { TriggerOptionRender } from '../components/TriggerOptionRender';
|
||||
|
||||
const collection = {
|
||||
name: 'workflows',
|
||||
@ -32,6 +33,9 @@ const collection = {
|
||||
'x-component': 'Select',
|
||||
'x-component-props': {
|
||||
options: `{{getTriggersOptions()}}`,
|
||||
optionRender: TriggerOptionRender,
|
||||
popupMatchSelectWidth: true,
|
||||
listHeight: 300,
|
||||
},
|
||||
required: true,
|
||||
} as ISchema,
|
||||
|
@ -28,7 +28,7 @@ const collectionModeOptions = [
|
||||
|
||||
export default class extends Trigger {
|
||||
title = `{{t("Collection event", { ns: "${NAMESPACE}" })}}`;
|
||||
description = `{{t("Event will be triggered on collection data row created, updated or deleted.", { ns: "${NAMESPACE}" })}}`;
|
||||
description = `{{t('Triggered when data changes in the collection, such as after adding, updating, or deleting a record. Unlike "Post-action event", Collection event listens for data changes rather than HTTP requests. Unless you understand the exact meaning, it is recommended to use "Post-action event".', { ns: "${NAMESPACE}" })}}`;
|
||||
fieldset = {
|
||||
collection: {
|
||||
...collection,
|
||||
|
@ -15,7 +15,7 @@ import { SCHEDULE_MODE } from './constants';
|
||||
export default class extends Trigger {
|
||||
sync = false;
|
||||
title = `{{t("Schedule event", { ns: "${NAMESPACE}" })}}`;
|
||||
description = `{{t("Event will be scheduled and triggered base on time conditions.", { ns: "${NAMESPACE}" })}}`;
|
||||
description = `{{t("Triggered according to preset time conditions. Suitable for one-time or periodic tasks, such as sending notifications and cleaning data on a schedule.", { ns: "${NAMESPACE}" })}}`;
|
||||
fieldset = {
|
||||
config: {
|
||||
type: 'void',
|
||||
|
@ -46,8 +46,8 @@
|
||||
"Full form data": "完整表单数据",
|
||||
"Select context": "选择上下文",
|
||||
"Collection event": "数据表事件",
|
||||
"Event will be triggered on collection data row created, updated or deleted.":
|
||||
"当数据表中的数据被新增、更新或删除时触发。",
|
||||
"Triggered when data changes in the collection, such as after adding, updating, or deleting a record. Unlike \"Post-action event\", Collection event listens for data changes rather than HTTP requests. Unless you understand the exact meaning, it is recommended to use \"Post-action event\".":
|
||||
"当数据表中的数据发生变化时触发,比如新增、更新或删除一条数据后。与“操作后事件”不同,数据表事件监听数据变动而不是 HTTP 请求,除非你明白确切含义,否则推荐使用“操作后事件”。",
|
||||
"Trigger on": "触发时机",
|
||||
"After record added": "新增数据后",
|
||||
"After record updated": "更新数据后",
|
||||
@ -61,7 +61,7 @@
|
||||
"Please select the associated fields that need to be accessed in subsequent nodes. With more than two levels of to-many associations may cause performance issue, please use with caution.":
|
||||
"请选中需要在后续节点中被访问的关系字段。超过两层的对多关联可能会导致性能问题,请谨慎使用。",
|
||||
"Schedule event": "定时任务",
|
||||
"Event will be scheduled and triggered base on time conditions.": "基于时间条件进行定时触发的事件。",
|
||||
"Triggered according to preset time conditions. Suitable for one-time or periodic tasks, such as sending notifications and cleaning data on a schedule.": "按预设的时间条件定时触发。适用于一次性或周期性的任务,如定时发送通知、清理数据等。",
|
||||
"Trigger mode": "触发模式",
|
||||
"Based on certain date": "自定义时间",
|
||||
"Based on date field of collection": "根据数据表时间字段",
|
||||
|
Loading…
x
Reference in New Issue
Block a user