feat(workflow): 移除工作流操作类型的触发事件 (#1561)
Reviewed-on: daoyoucloud/tachybase#1561 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:
		
							parent
							
								
									569dbf2423
								
							
						
					
					
						commit
						04cd8135ca
					
				@ -4,7 +4,6 @@ import { Registry } from '@tachybase/utils/client';
 | 
			
		||||
 | 
			
		||||
import { WorkflowLink } from './components/WorkflowLink';
 | 
			
		||||
import { ExecutionPage } from './ExecutionPage';
 | 
			
		||||
import { PluginActionTrigger } from './features/action-trigger';
 | 
			
		||||
import { PluginAggregate } from './features/aggregate';
 | 
			
		||||
import PluginApproval from './features/approval';
 | 
			
		||||
import PluginWorkflowDataMappingClient from './features/data-mapping';
 | 
			
		||||
@ -86,7 +85,6 @@ export class PluginWorkflow extends Plugin {
 | 
			
		||||
    await this.pm.add(PluginDaynamicCalculation);
 | 
			
		||||
    await this.pm.add(PluginDelay);
 | 
			
		||||
    await this.pm.add(PluginAggregate);
 | 
			
		||||
    await this.pm.add(PluginActionTrigger);
 | 
			
		||||
    await this.pm.add(PluginWorkflowJsonParseClient);
 | 
			
		||||
    await this.pm.add(PluginWorkflowJSParseClient);
 | 
			
		||||
    await this.pm.add(PluginWorkflowDataMappingClient);
 | 
			
		||||
 | 
			
		||||
@ -1,134 +0,0 @@
 | 
			
		||||
import {
 | 
			
		||||
  SchemaInitializerItemType,
 | 
			
		||||
  useCollectionDataSource,
 | 
			
		||||
  useCollectionManager_deprecated,
 | 
			
		||||
  useCompile,
 | 
			
		||||
} from '@tachybase/client';
 | 
			
		||||
import { useForm } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import { CollectionBlockInitializer } from '../../components';
 | 
			
		||||
import { useWorkflowAnyExecuted } from '../../hooks';
 | 
			
		||||
import { lang, NAMESPACE, tval } from '../../locale';
 | 
			
		||||
import { Trigger } from '../../triggers';
 | 
			
		||||
import { getCollectionFieldOptions } from '../../variable';
 | 
			
		||||
 | 
			
		||||
export class ActionTrigger extends Trigger {
 | 
			
		||||
  title = tval('Action event(deprecated)');
 | 
			
		||||
  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}" })}}`;
 | 
			
		||||
  fieldset = {
 | 
			
		||||
    collection: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      required: true,
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'DataSourceCollectionCascader',
 | 
			
		||||
      'x-disabled': '{{ useWorkflowAnyExecuted() }}',
 | 
			
		||||
      title: `{{t("Collection", { ns: "${NAMESPACE}" })}}`,
 | 
			
		||||
      description: `{{t("Which collection record belongs to.", { ns: "${NAMESPACE}" })}}`,
 | 
			
		||||
      'x-reactions': [
 | 
			
		||||
        {
 | 
			
		||||
          target: 'appends',
 | 
			
		||||
          effects: ['onFieldValueChange'],
 | 
			
		||||
          fulfill: {
 | 
			
		||||
            state: {
 | 
			
		||||
              value: [],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
    appends: {
 | 
			
		||||
      type: 'array',
 | 
			
		||||
      title: `{{t("Associations to use", { ns: "${NAMESPACE}" })}}`,
 | 
			
		||||
      description: `{{t("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.", { ns: "workflow" })}}`,
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'AppendsTreeSelect',
 | 
			
		||||
      'x-component-props': {
 | 
			
		||||
        title: 'Preload associations',
 | 
			
		||||
        multiple: true,
 | 
			
		||||
        useCollection() {
 | 
			
		||||
          const { values } = useForm();
 | 
			
		||||
          return values?.collection;
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      'x-reactions': [
 | 
			
		||||
        {
 | 
			
		||||
          dependencies: ['collection'],
 | 
			
		||||
          fulfill: {
 | 
			
		||||
            state: {
 | 
			
		||||
              visible: '{{!!$deps[0]}}',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  scope = {
 | 
			
		||||
    useCollectionDataSource,
 | 
			
		||||
    useWorkflowAnyExecuted,
 | 
			
		||||
  };
 | 
			
		||||
  isActionTriggerable = (config, context) => {
 | 
			
		||||
    return ['create', 'update', 'customize:update', 'customize:triggerWorkflows'].includes(context.action);
 | 
			
		||||
  };
 | 
			
		||||
  useVariables(config, options) {
 | 
			
		||||
    // eslint-disable-next-line react-hooks/rules-of-hooks
 | 
			
		||||
    const compile = useCompile();
 | 
			
		||||
    // eslint-disable-next-line react-hooks/rules-of-hooks
 | 
			
		||||
    const { getCollectionFields } = useCollectionManager_deprecated();
 | 
			
		||||
    // eslint-disable-next-line react-hooks/rules-of-hooks
 | 
			
		||||
    const langTriggerData = lang('Trigger data');
 | 
			
		||||
    // eslint-disable-next-line react-hooks/rules-of-hooks
 | 
			
		||||
    const langUserSubmittedForm = lang('User submitted action');
 | 
			
		||||
    // eslint-disable-next-line react-hooks/rules-of-hooks
 | 
			
		||||
    const langRoleSubmittedForm = lang('Role of user submitted action');
 | 
			
		||||
    const rootFields = [
 | 
			
		||||
      {
 | 
			
		||||
        collectionName: config.collection,
 | 
			
		||||
        name: 'data',
 | 
			
		||||
        type: 'hasOne',
 | 
			
		||||
        target: config.collection,
 | 
			
		||||
        uiSchema: {
 | 
			
		||||
          title: langTriggerData,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        collectionName: 'users',
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        type: 'hasOne',
 | 
			
		||||
        target: 'users',
 | 
			
		||||
        uiSchema: {
 | 
			
		||||
          title: langUserSubmittedForm,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        name: 'roleName',
 | 
			
		||||
        uiSchema: {
 | 
			
		||||
          title: langRoleSubmittedForm,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
    const result = getCollectionFieldOptions({
 | 
			
		||||
      // depth,
 | 
			
		||||
      appends: ['data', 'user', ...(config.appends?.map((item) => `data.${item}`) || [])],
 | 
			
		||||
      ...options,
 | 
			
		||||
      fields: rootFields,
 | 
			
		||||
      compile,
 | 
			
		||||
      getCollectionFields,
 | 
			
		||||
    });
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  useInitializers(config): SchemaInitializerItemType | null {
 | 
			
		||||
    if (!config.collection) {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      name: 'triggerData',
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      key: 'triggerData',
 | 
			
		||||
      title: `{{t("Trigger data", { ns: "${NAMESPACE}" })}}`,
 | 
			
		||||
      Component: CollectionBlockInitializer,
 | 
			
		||||
      collection: config.collection,
 | 
			
		||||
      dataPath: '$context.data',
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,676 +0,0 @@
 | 
			
		||||
import {
 | 
			
		||||
  apiCreateRecordTriggerFormEvent,
 | 
			
		||||
  apiCreateWorkflow,
 | 
			
		||||
  apiDeleteWorkflow,
 | 
			
		||||
  apiGetDataSourceCount,
 | 
			
		||||
  apiGetWorkflow,
 | 
			
		||||
  apiUpdateWorkflowTrigger,
 | 
			
		||||
  appendJsonCollectionName,
 | 
			
		||||
  FormEventTriggerNode,
 | 
			
		||||
  generalWithNoRelationalFields,
 | 
			
		||||
  WorkflowListRecords,
 | 
			
		||||
} from '@tachybase/plugin-workflow-test/e2e';
 | 
			
		||||
import { expect, test } from '@tachybase/test/e2e';
 | 
			
		||||
import { dayjs } from '@tachybase/utils';
 | 
			
		||||
 | 
			
		||||
import { faker } from '@faker-js/faker';
 | 
			
		||||
 | 
			
		||||
test.describe('Configuration page to configure the Trigger node', () => {
 | 
			
		||||
  test('Form Submit Button Binding Workflow Add Data Trigger', async ({
 | 
			
		||||
    page,
 | 
			
		||||
    mockPage,
 | 
			
		||||
    mockCollections,
 | 
			
		||||
    mockRecords,
 | 
			
		||||
  }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    await page.goto(`admin/workflow/workflows/${workflowId}`);
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
 | 
			
		||||
    await formEventTriggerNode.nodeConfigure.click();
 | 
			
		||||
    await formEventTriggerNode.collectionDropDown.click();
 | 
			
		||||
    await page.getByRole('menuitemcheckbox', { name: 'Main right' }).click();
 | 
			
		||||
    await page.getByRole('menuitemcheckbox', { name: triggerNodeCollectionDisplayName }).click();
 | 
			
		||||
    await formEventTriggerNode.submitButton.click();
 | 
			
		||||
 | 
			
		||||
    //配置录入数据区块
 | 
			
		||||
    const newPage = mockPage();
 | 
			
		||||
    await newPage.goto();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel('schema-initializer-Grid-page:addBlock').hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'table Table' }).hover();
 | 
			
		||||
    const dataSourcesCount = await apiGetDataSourceCount();
 | 
			
		||||
    if (dataSourcesCount > 1) {
 | 
			
		||||
      await page.getByRole('menuitem', { name: 'Main right' }).hover();
 | 
			
		||||
    }
 | 
			
		||||
    await page.getByRole('menuitem', { name: `${triggerNodeCollectionDisplayName}` }).click();
 | 
			
		||||
 | 
			
		||||
    // 移开鼠标,关闭菜单
 | 
			
		||||
    await page.mouse.move(300, 0);
 | 
			
		||||
 | 
			
		||||
    await page.getByText('Configure columns').hover();
 | 
			
		||||
    await page.getByText(triggerNodeFieldDisplayName).click();
 | 
			
		||||
    await page.getByText('Configure actions').hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch').click();
 | 
			
		||||
    await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeEnabled();
 | 
			
		||||
    await page.getByLabel(`action-Action-Add new-create-${triggerNodeCollectionName}-table`).click();
 | 
			
		||||
    await page.getByLabel(`schema-initializer-Grid-popup:addNew:addBlock-${triggerNodeCollectionName}`).hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'form Form' }).click();
 | 
			
		||||
    // 移开鼠标,关闭菜单
 | 
			
		||||
    await page.mouse.move(300, 0);
 | 
			
		||||
    await page
 | 
			
		||||
      .getByLabel(`schema-initializer-ActionBar-createForm:configureActions-${triggerNodeCollectionName}`)
 | 
			
		||||
      .hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'Submit' }).click();
 | 
			
		||||
    // 绑定工作流
 | 
			
		||||
    await page.getByLabel(`schema-initializer-Grid-form:configureFields-${triggerNodeCollectionName}`).hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: `${triggerNodeFieldDisplayName}` }).click();
 | 
			
		||||
    await page.mouse.move(300, 0);
 | 
			
		||||
    await page.getByLabel(`action-Action-Submit-submit-${triggerNodeCollectionName}-form`).hover();
 | 
			
		||||
    await page
 | 
			
		||||
      .getByRole('button', {
 | 
			
		||||
        name: `designer-schema-settings-Action-actionSettings:createSubmit-${triggerNodeCollectionName}`,
 | 
			
		||||
      })
 | 
			
		||||
      .hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'Bind workflows' }).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'plus Add workflow' }).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'Select workflow' }).click();
 | 
			
		||||
    await page.getByRole('option', { name: workFlowName }).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'Submit', exact: true }).click();
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:进入“数据区块”-“添加”按钮,填写表单,点击“确定”按钮
 | 
			
		||||
    const fieldData = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    await page.getByRole('textbox').fill(fieldData);
 | 
			
		||||
    await page.getByLabel(`action-Action-Submit-submit-${triggerNodeCollectionName}-form`, { exact: true }).click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
    // 3、预期结果:触发次数为1
 | 
			
		||||
    const getWorkflow = await apiGetWorkflow(workflowId);
 | 
			
		||||
    const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
 | 
			
		||||
    const getWorkflowExecuted = getWorkflowObj.executed;
 | 
			
		||||
    expect(getWorkflowExecuted).toBe(1);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('Form Submit to Workflow Button Add Data Trigger', async ({ page, mockPage, mockCollections, mockRecords }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    await page.goto(`admin/workflow/workflows/${workflowId}`);
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
 | 
			
		||||
    await formEventTriggerNode.nodeConfigure.click();
 | 
			
		||||
    await formEventTriggerNode.collectionDropDown.click();
 | 
			
		||||
    await page.getByRole('menuitemcheckbox', { name: 'Main right' }).click();
 | 
			
		||||
    await page.getByRole('menuitemcheckbox', { name: triggerNodeCollectionDisplayName }).click();
 | 
			
		||||
    await formEventTriggerNode.submitButton.click();
 | 
			
		||||
 | 
			
		||||
    //配置录入数据区块
 | 
			
		||||
    const newPage = mockPage();
 | 
			
		||||
    await newPage.goto();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel('schema-initializer-Grid-page:addBlock').hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'table Table' }).hover();
 | 
			
		||||
    const dataSourcesCount = await apiGetDataSourceCount();
 | 
			
		||||
    if (dataSourcesCount > 1) {
 | 
			
		||||
      await page.getByRole('menuitem', { name: 'Main right' }).hover();
 | 
			
		||||
    }
 | 
			
		||||
    await page.getByRole('menuitem', { name: `${triggerNodeCollectionDisplayName}` }).click();
 | 
			
		||||
 | 
			
		||||
    // 移开鼠标,关闭菜单
 | 
			
		||||
    await page.mouse.move(300, 0);
 | 
			
		||||
 | 
			
		||||
    await page.getByText('Configure columns').hover();
 | 
			
		||||
    await page.getByText(triggerNodeFieldDisplayName).click();
 | 
			
		||||
    await page.getByText('Configure actions').hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch').click();
 | 
			
		||||
    await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeEnabled();
 | 
			
		||||
 | 
			
		||||
    await page.getByLabel(`action-Action-Add new-create-${triggerNodeCollectionName}-table`).click();
 | 
			
		||||
    await page.getByLabel(`schema-initializer-Grid-popup:addNew:addBlock-${triggerNodeCollectionName}`).hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'form Form' }).click();
 | 
			
		||||
 | 
			
		||||
    // 移开鼠标,关闭菜单
 | 
			
		||||
    await page.mouse.move(300, 0);
 | 
			
		||||
 | 
			
		||||
    // 绑定工作流
 | 
			
		||||
    await page
 | 
			
		||||
      .getByLabel(`schema-initializer-ActionBar-createForm:configureActions-${triggerNodeCollectionName}`)
 | 
			
		||||
      .hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'Customize' }).hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'Submit to workflow' }).click();
 | 
			
		||||
    await page.getByLabel(`schema-initializer-Grid-form:configureFields-${triggerNodeCollectionName}`).hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: `${triggerNodeFieldDisplayName}` }).click();
 | 
			
		||||
    await page.mouse.move(300, 0);
 | 
			
		||||
    await page.getByRole('button', { name: 'Submit to workflow' }).hover();
 | 
			
		||||
    await page
 | 
			
		||||
      .getByRole('button', {
 | 
			
		||||
        name: `designer-schema-settings-Action-Action.Designer-${triggerNodeCollectionName}`,
 | 
			
		||||
      })
 | 
			
		||||
      .hover();
 | 
			
		||||
    await page.getByRole('menuitem', { name: 'Bind workflows' }).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'plus Add workflow' }).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'Select workflow' }).click();
 | 
			
		||||
    await page.getByRole('option', { name: workFlowName }).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'Submit', exact: true }).click();
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:进入“数据区块”-“添加”按钮,填写表单,点击“确定”按钮
 | 
			
		||||
    const fieldData = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    await page.getByRole('textbox').fill(fieldData);
 | 
			
		||||
    await page
 | 
			
		||||
      .getByLabel(`action-Action-Submit to workflow-customize:triggerWorkflows-${triggerNodeCollectionName}-form`)
 | 
			
		||||
      .click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
    // 3、预期结果:触发次数为1
 | 
			
		||||
    const getWorkflow = await apiGetWorkflow(workflowId);
 | 
			
		||||
    const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
 | 
			
		||||
    const getWorkflowExecuted = getWorkflowObj.executed;
 | 
			
		||||
    expect(getWorkflowExecuted).toBe(1);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Configuration Page Path Jump Workflow Management Page', () => {
 | 
			
		||||
  test('Action event Workflow Configuration Page Path Jump Workflow Management Page', async ({
 | 
			
		||||
    page,
 | 
			
		||||
    mockPage,
 | 
			
		||||
    mockCollections,
 | 
			
		||||
    mockRecords,
 | 
			
		||||
  }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    // const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    // const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    // const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    // const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    // await mockCollections(appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText).collections);
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    await page.goto(`admin/workflow/workflows/${workflowId}`);
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:跳转到工作流管理页面
 | 
			
		||||
    await page.getByRole('link', { name: 'Workflow' }).click();
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:跳转路径正确
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('Action event Workflow History Version Configuration Page Path Jump Workflow Management Page', async ({
 | 
			
		||||
    page,
 | 
			
		||||
    mockPage,
 | 
			
		||||
    mockCollections,
 | 
			
		||||
    mockRecords,
 | 
			
		||||
  }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
    const WorkflowKey = workflowObj.key;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
 | 
			
		||||
    const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
 | 
			
		||||
    const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:添加数据触发工作流
 | 
			
		||||
    const triggerNodeCollectionRecordOne =
 | 
			
		||||
      triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    const triggerWorkflows = WorkflowKey;
 | 
			
		||||
    const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
 | 
			
		||||
      triggerNodeCollectionName,
 | 
			
		||||
      triggerWorkflows,
 | 
			
		||||
      { orgname: triggerNodeCollectionRecordOne },
 | 
			
		||||
    );
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    await page.goto(`admin/workflow/workflows/${workflowId}`);
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel('more').click();
 | 
			
		||||
    await page.getByLabel('revision').click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    //元素重复
 | 
			
		||||
    await page.getByLabel('version', { exact: true }).click();
 | 
			
		||||
    await page.getByLabel('version-1').click();
 | 
			
		||||
    await page.getByRole('link', { name: 'Workflow' }).click();
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:跳转路径正确
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('Action event Workflow Execution Log Page Path Jump Workflow Management Page', async ({
 | 
			
		||||
    page,
 | 
			
		||||
    mockPage,
 | 
			
		||||
    mockCollections,
 | 
			
		||||
    mockRecords,
 | 
			
		||||
  }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
    const WorkflowKey = workflowObj.key;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
 | 
			
		||||
    const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
 | 
			
		||||
    const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:添加数据触发工作流
 | 
			
		||||
    const triggerNodeCollectionRecordOne =
 | 
			
		||||
      triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    const triggerWorkflows = WorkflowKey;
 | 
			
		||||
    const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
 | 
			
		||||
      triggerNodeCollectionName,
 | 
			
		||||
      triggerWorkflows,
 | 
			
		||||
      { orgname: triggerNodeCollectionRecordOne },
 | 
			
		||||
    );
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    await page.goto('/admin/settings/workflow');
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    const workflowListRecords = new WorkflowListRecords(page, workFlowName);
 | 
			
		||||
    await workflowListRecords.executionCountPopup.click();
 | 
			
		||||
    await page.getByText('View').click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByRole('link', { name: 'Workflow', exact: true }).click();
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:跳转路径正确
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test.skip('Action event Workflow Execution Log Page Path Jump Execution Log Screen', async ({
 | 
			
		||||
    page,
 | 
			
		||||
    mockCollections,
 | 
			
		||||
    mockRecords,
 | 
			
		||||
  }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
    const WorkflowKey = workflowObj.key;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
 | 
			
		||||
    const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
 | 
			
		||||
    const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:添加数据触发工作流
 | 
			
		||||
    const triggerNodeCollectionRecordOne =
 | 
			
		||||
      triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    const triggerWorkflows = WorkflowKey;
 | 
			
		||||
    const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
 | 
			
		||||
      triggerNodeCollectionName,
 | 
			
		||||
      triggerWorkflows,
 | 
			
		||||
      { orgname: triggerNodeCollectionRecordOne },
 | 
			
		||||
    );
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    await page.goto('/admin/settings/workflow');
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    const workflowListRecords = new WorkflowListRecords(page, workFlowName);
 | 
			
		||||
    await workflowListRecords.executionCountPopup.click();
 | 
			
		||||
    await page.getByText('View').click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    //跳转其他执行日志界面,元素无法定位
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:跳转路径正确
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    // expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Configuration page version switching', () => {});
 | 
			
		||||
 | 
			
		||||
test.describe('Configuration page disable enable', () => {
 | 
			
		||||
  test('Action event Workflow Add Data Trigger Disable Do Not Trigger', async ({
 | 
			
		||||
    page,
 | 
			
		||||
    mockCollections,
 | 
			
		||||
    mockRecords,
 | 
			
		||||
  }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: false,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
    const WorkflowKey = workflowObj.key;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
 | 
			
		||||
    const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
 | 
			
		||||
    const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:添加数据触发工作流
 | 
			
		||||
    const triggerNodeCollectionRecordOne =
 | 
			
		||||
      triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    const triggerWorkflows = WorkflowKey;
 | 
			
		||||
    const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
 | 
			
		||||
      triggerNodeCollectionName,
 | 
			
		||||
      triggerWorkflows,
 | 
			
		||||
      { orgname: triggerNodeCollectionRecordOne },
 | 
			
		||||
    );
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:触发次数为1
 | 
			
		||||
    let getWorkflow = await apiGetWorkflow(workflowId);
 | 
			
		||||
    let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
 | 
			
		||||
    let getWorkflowExecuted = getWorkflowObj.executed;
 | 
			
		||||
    expect(getWorkflowExecuted).toBe(0);
 | 
			
		||||
 | 
			
		||||
    await page.goto(`admin/workflow/workflows/${workflowId}`);
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByRole('switch', { name: 'On Off' }).click();
 | 
			
		||||
 | 
			
		||||
    await apiCreateRecordTriggerFormEvent(triggerNodeCollectionName, triggerWorkflows, {
 | 
			
		||||
      orgname: triggerNodeCollectionRecordOne + '1',
 | 
			
		||||
    });
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    getWorkflow = await apiGetWorkflow(workflowId);
 | 
			
		||||
    getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
 | 
			
		||||
    getWorkflowExecuted = getWorkflowObj.executed;
 | 
			
		||||
    expect(getWorkflowExecuted).toBe(1);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('Action event Workflow Add Data Trigger Disable Enable Post Trigger', async ({
 | 
			
		||||
    page,
 | 
			
		||||
    mockCollections,
 | 
			
		||||
    mockRecords,
 | 
			
		||||
  }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
    const WorkflowKey = workflowObj.key;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
 | 
			
		||||
    const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
 | 
			
		||||
    const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:添加数据触发工作流
 | 
			
		||||
    const triggerNodeCollectionRecordOne =
 | 
			
		||||
      triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    const triggerWorkflows = WorkflowKey;
 | 
			
		||||
    const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
 | 
			
		||||
      triggerNodeCollectionName,
 | 
			
		||||
      triggerWorkflows,
 | 
			
		||||
      { orgname: triggerNodeCollectionRecordOne },
 | 
			
		||||
    );
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:触发次数为1
 | 
			
		||||
    let getWorkflow = await apiGetWorkflow(workflowId);
 | 
			
		||||
    let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
 | 
			
		||||
    let getWorkflowExecuted = getWorkflowObj.executed;
 | 
			
		||||
    expect(getWorkflowExecuted).toBe(1);
 | 
			
		||||
 | 
			
		||||
    await page.goto(`admin/workflow/workflows/${workflowId}`);
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByRole('switch', { name: 'On Off' }).click();
 | 
			
		||||
 | 
			
		||||
    await apiCreateRecordTriggerFormEvent(triggerNodeCollectionName, triggerWorkflows, {
 | 
			
		||||
      orgname: triggerNodeCollectionRecordOne + '1',
 | 
			
		||||
    });
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    getWorkflow = await apiGetWorkflow(workflowId);
 | 
			
		||||
    getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
 | 
			
		||||
    getWorkflowExecuted = getWorkflowObj.executed;
 | 
			
		||||
    expect(getWorkflowExecuted).toBe(1);
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Configuration page execution history', () => {});
 | 
			
		||||
 | 
			
		||||
test.describe('Configuration page copy to new version', () => {
 | 
			
		||||
  test('Copy the action event of the Configuration Trigger node', async ({ page, mockCollections, mockRecords }) => {
 | 
			
		||||
    //数据表后缀标识
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
 | 
			
		||||
    //创建触发器节点数据表
 | 
			
		||||
    const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
 | 
			
		||||
    const triggerNodeFieldName = 'orgname';
 | 
			
		||||
    const triggerNodeFieldDisplayName = '公司名称(单行文本)';
 | 
			
		||||
    await mockCollections(
 | 
			
		||||
      appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
 | 
			
		||||
        .collections,
 | 
			
		||||
    );
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
    const WorkflowKey = workflowObj.key;
 | 
			
		||||
 | 
			
		||||
    //配置工作流触发器
 | 
			
		||||
    const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
 | 
			
		||||
    const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
 | 
			
		||||
    const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
 | 
			
		||||
 | 
			
		||||
    // 2、测试步骤:添加数据触发工作流
 | 
			
		||||
    const triggerNodeCollectionRecordOne =
 | 
			
		||||
      triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
 | 
			
		||||
    const triggerWorkflows = WorkflowKey;
 | 
			
		||||
    const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
 | 
			
		||||
      triggerNodeCollectionName,
 | 
			
		||||
      triggerWorkflows,
 | 
			
		||||
      { orgname: triggerNodeCollectionRecordOne },
 | 
			
		||||
    );
 | 
			
		||||
    await page.waitForTimeout(1000);
 | 
			
		||||
 | 
			
		||||
    await page.goto(`admin/workflow/workflows/${workflowId}`);
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel('more').click();
 | 
			
		||||
    await page.getByLabel('revision').click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:新版本工作流配置内容同旧版本一样
 | 
			
		||||
    const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
 | 
			
		||||
    await formEventTriggerNode.nodeConfigure.click();
 | 
			
		||||
    await expect(
 | 
			
		||||
      page
 | 
			
		||||
        .getByLabel('block-item-DataSourceCollectionCascader-workflows-Collection')
 | 
			
		||||
        .getByText(`Main / ${triggerNodeCollectionDisplayName}`),
 | 
			
		||||
    ).toBeVisible();
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Configuration page  delete version', () => {});
 | 
			
		||||
 | 
			
		||||
test.describe('Node Add Modify Delete', () => {});
 | 
			
		||||
@ -1,179 +0,0 @@
 | 
			
		||||
import {
 | 
			
		||||
  apiCreateRecordTriggerFormEvent,
 | 
			
		||||
  apiCreateWorkflow,
 | 
			
		||||
  apiDeleteWorkflow,
 | 
			
		||||
  apiGetWorkflow,
 | 
			
		||||
  apiUpdateWorkflowTrigger,
 | 
			
		||||
  appendJsonCollectionName,
 | 
			
		||||
  CreateWorkFlow,
 | 
			
		||||
  EditWorkFlow,
 | 
			
		||||
  FormEventTriggerNode,
 | 
			
		||||
  generalWithNoRelationalFields,
 | 
			
		||||
  WorkflowListRecords,
 | 
			
		||||
} from '@tachybase/plugin-workflow-test/e2e';
 | 
			
		||||
import { expect, test } from '@tachybase/test/e2e';
 | 
			
		||||
import { dayjs } from '@tachybase/utils';
 | 
			
		||||
 | 
			
		||||
import { faker } from '@faker-js/faker';
 | 
			
		||||
 | 
			
		||||
test.describe('Filter', () => {
 | 
			
		||||
  test('filter workflow name', async ({ page }) => {
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
 | 
			
		||||
    // 2、筛选工作流
 | 
			
		||||
    await page.goto('/admin/settings/workflow');
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
 | 
			
		||||
    await page.getByRole('textbox').fill(workFlowName);
 | 
			
		||||
    await page.getByRole('button', { name: 'Submit' }).click();
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:列表中出现筛选的工作流
 | 
			
		||||
    await expect(page.getByText(workFlowName)).toBeAttached();
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Add new', () => {
 | 
			
		||||
  test('add new Action event', async ({ page }) => {
 | 
			
		||||
    // 添加工作流
 | 
			
		||||
    await page.goto('/admin/settings/workflow');
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel('action-Action-Add new-workflows').click();
 | 
			
		||||
    const createWorkFlow = new CreateWorkFlow(page);
 | 
			
		||||
    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.getByLabel('action-Action-Submit-workflows').click();
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:列表中出现新建的工作流
 | 
			
		||||
    await expect(page.getByText(workFlowName)).toBeVisible();
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
 | 
			
		||||
    await page.getByRole('textbox').fill(workFlowName);
 | 
			
		||||
    await page.getByRole('button', { name: 'Submit' }).click();
 | 
			
		||||
    await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'OK', exact: true }).click();
 | 
			
		||||
    await expect(page.getByText(workFlowName)).toBeHidden();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Sync', () => {});
 | 
			
		||||
 | 
			
		||||
test.describe('Delete', () => {
 | 
			
		||||
  test('delete Action event', async ({ page }) => {
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
 | 
			
		||||
    // 删除工作流
 | 
			
		||||
    await page.goto('/admin/settings/workflow');
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
 | 
			
		||||
    await page.getByRole('textbox').fill(workFlowName);
 | 
			
		||||
    await page.getByRole('button', { name: 'Submit' }).click();
 | 
			
		||||
    await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'OK', exact: true }).click();
 | 
			
		||||
 | 
			
		||||
    // 3、预期结果:列表中出现筛选的工作流
 | 
			
		||||
    await expect(page.getByText(workFlowName)).toBeHidden();
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Edit', () => {
 | 
			
		||||
  test('edit Action event name', async ({ page }) => {
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
    let workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
 | 
			
		||||
    // 编辑工作流
 | 
			
		||||
    await page.goto('/admin/settings/workflow');
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
 | 
			
		||||
    const editWorkFlow = new EditWorkFlow(page, workFlowName);
 | 
			
		||||
    workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    await editWorkFlow.name.fill(workFlowName);
 | 
			
		||||
    await page.getByLabel('action-Action-Submit-workflows').click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    // 3、预期结果:编辑成功,列表中出现编辑后的工作流
 | 
			
		||||
    await expect(page.getByText(workFlowName)).toBeAttached();
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Duplicate', () => {
 | 
			
		||||
  test('Duplicate Action event triggers with only unconfigured trigger nodes', async ({ page }) => {
 | 
			
		||||
    //添加工作流
 | 
			
		||||
    const triggerNodeAppendText = faker.string.alphanumeric(5);
 | 
			
		||||
    const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
 | 
			
		||||
    const workflowData = {
 | 
			
		||||
      current: true,
 | 
			
		||||
      options: { deleteExecutionOnStatus: [] },
 | 
			
		||||
      title: workFlowName,
 | 
			
		||||
      type: 'action',
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    };
 | 
			
		||||
    const workflow = await apiCreateWorkflow(workflowData);
 | 
			
		||||
    const workflowObj = JSON.parse(JSON.stringify(workflow));
 | 
			
		||||
    const workflowId = workflowObj.id;
 | 
			
		||||
 | 
			
		||||
    // 2、复制工作流
 | 
			
		||||
    await page.goto('/admin/settings/workflow');
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    await page.getByLabel(`action-Action.Link-Duplicate-workflows-${workFlowName}`).click();
 | 
			
		||||
    await page.getByLabel(`action-Action-Submit-workflows-${workFlowName}`).click();
 | 
			
		||||
    await page.waitForLoadState('networkidle');
 | 
			
		||||
    // 3、预期结果:列表中出现筛选的工作流
 | 
			
		||||
    await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
 | 
			
		||||
    await page.getByRole('textbox').fill(workFlowName);
 | 
			
		||||
    await page.getByRole('button', { name: 'Submit', exact: true }).click();
 | 
			
		||||
    await expect(page.getByText(`${workFlowName} copy`)).toBeAttached();
 | 
			
		||||
 | 
			
		||||
    // 4、后置处理:删除工作流
 | 
			
		||||
    await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}  copy`).click();
 | 
			
		||||
    await page.getByRole('button', { name: 'OK', exact: true }).click();
 | 
			
		||||
    await expect(page.getByText(`${workFlowName} copy`)).toBeHidden();
 | 
			
		||||
    await apiDeleteWorkflow(workflowId);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test.describe('Executed', () => {});
 | 
			
		||||
@ -1,92 +0,0 @@
 | 
			
		||||
import { Plugin, SchemaInitializerItemType } from '@tachybase/client';
 | 
			
		||||
 | 
			
		||||
import WorkflowPlugin, { useRecordTriggerWorkflowsActionProps, useTriggerWorkflowsActionProps } from '../..';
 | 
			
		||||
import { ActionTrigger } from './ActionTrigger';
 | 
			
		||||
 | 
			
		||||
const submitToWorkflowActionInitializer: SchemaInitializerItemType = {
 | 
			
		||||
  name: 'submitToWorkflow',
 | 
			
		||||
  title: '{{t("Submit to workflow", { ns: "workflow" })}}',
 | 
			
		||||
  Component: 'CustomizeActionInitializer',
 | 
			
		||||
  schema: {
 | 
			
		||||
    title: '{{t("Submit to workflow", { ns: "workflow" })}}',
 | 
			
		||||
    'x-component': 'Action',
 | 
			
		||||
    'x-use-component-props': 'useTriggerWorkflowsActionProps',
 | 
			
		||||
    'x-designer': 'Action.Designer',
 | 
			
		||||
    'x-action-settings': {
 | 
			
		||||
      // assignedValues: {},
 | 
			
		||||
      skipValidator: false,
 | 
			
		||||
      onSuccess: {
 | 
			
		||||
        manualClose: true,
 | 
			
		||||
        redirecting: false,
 | 
			
		||||
        successMessage: '{{t("Submitted successfully")}}',
 | 
			
		||||
      },
 | 
			
		||||
      triggerWorkflows: [],
 | 
			
		||||
    },
 | 
			
		||||
    'x-action': 'customize:triggerWorkflows',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const recordTriggerWorkflowActionInitializer: SchemaInitializerItemType = {
 | 
			
		||||
  name: 'submitToWorkflow',
 | 
			
		||||
  title: '{{t("Submit to workflow", { ns: "workflow" })}}',
 | 
			
		||||
  Component: 'CustomizeActionInitializer',
 | 
			
		||||
  schema: {
 | 
			
		||||
    title: '{{t("Submit to workflow", { ns: "workflow" })}}',
 | 
			
		||||
    'x-component': 'Action',
 | 
			
		||||
    'x-use-component-props': 'useRecordTriggerWorkflowsActionProps',
 | 
			
		||||
    'x-designer': 'Action.Designer',
 | 
			
		||||
    'x-action-settings': {
 | 
			
		||||
      onSuccess: {
 | 
			
		||||
        manualClose: true,
 | 
			
		||||
        redirecting: false,
 | 
			
		||||
        successMessage: '{{t("Submitted successfully")}}',
 | 
			
		||||
      },
 | 
			
		||||
      triggerWorkflows: [],
 | 
			
		||||
    },
 | 
			
		||||
    'x-action': 'customize:triggerWorkflows',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const recordTriggerWorkflowActionLinkInitializer = {
 | 
			
		||||
  ...recordTriggerWorkflowActionInitializer,
 | 
			
		||||
  schema: {
 | 
			
		||||
    ...recordTriggerWorkflowActionInitializer.schema,
 | 
			
		||||
    'x-component': 'Action.Link',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export class PluginActionTrigger extends Plugin {
 | 
			
		||||
  async load() {
 | 
			
		||||
    const workflow = this.app.pm.get('workflow') as WorkflowPlugin;
 | 
			
		||||
    workflow.registerTrigger('action', ActionTrigger);
 | 
			
		||||
 | 
			
		||||
    this.app.addScopes({
 | 
			
		||||
      useTriggerWorkflowsActionProps,
 | 
			
		||||
      useRecordTriggerWorkflowsActionProps,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const FormActionInitializers = this.app.schemaInitializerManager.get('FormActionInitializers');
 | 
			
		||||
    FormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
 | 
			
		||||
 | 
			
		||||
    const CreateFormActionInitializers = this.app.schemaInitializerManager.get('createForm:configureActions');
 | 
			
		||||
    CreateFormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
 | 
			
		||||
 | 
			
		||||
    const UpdateFormActionInitializers = this.app.schemaInitializerManager.get('editForm:configureActions');
 | 
			
		||||
    UpdateFormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
 | 
			
		||||
 | 
			
		||||
    const DetailsActionInitializers = this.app.schemaInitializerManager.get('detailsWithPaging:configureActions');
 | 
			
		||||
    DetailsActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionInitializer);
 | 
			
		||||
 | 
			
		||||
    const ReadPrettyFormActionInitializers = this.app.schemaInitializerManager.get('details:configureActions');
 | 
			
		||||
    ReadPrettyFormActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionInitializer);
 | 
			
		||||
 | 
			
		||||
    const TableActionColumnInitializers = this.app.schemaInitializerManager.get('table:configureItemActions');
 | 
			
		||||
    TableActionColumnInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
 | 
			
		||||
 | 
			
		||||
    const GridCardItemActionInitializers = this.app.schemaInitializerManager.get('gridCard:configureItemActions');
 | 
			
		||||
    GridCardItemActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
 | 
			
		||||
 | 
			
		||||
    const ListItemActionInitializers = this.app.schemaInitializerManager.get('list:configureItemActions');
 | 
			
		||||
    ListItemActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -28,7 +28,6 @@
 | 
			
		||||
    "Workflow will be triggered after submitting succeeded.": "제출 성공 후 워크플로우가 트리거됩니다.",
 | 
			
		||||
    "Workflow will be triggered after saving succeeded.": "저장 성공 후 워크플로우가 트리거됩니다.",
 | 
			
		||||
    "Workflow will be triggered directly once the button is clicked, without data saving.": "버튼을 클릭하면 데이터 저장 없이 워크플로우가 직접 트리거됩니다.",
 | 
			
		||||
    "Submit to workflow": "워크플로우에 제출",
 | 
			
		||||
    "Add workflow": "워크플로우 추가",
 | 
			
		||||
    "Select workflow": "워크플로우 선택",
 | 
			
		||||
    "Trigger data context": "트리거 데이터 컨텍스트",
 | 
			
		||||
@ -244,4 +243,4 @@
 | 
			
		||||
    "SQL action": "SQL 작업",
 | 
			
		||||
    "Execute a SQL statement in database": "데이터베이스에서 SQL 문을 실행합니다",
 | 
			
		||||
    "Usage of SQL query result is not supported yet.": "아직 SQL 쿼리 결과의 사용은 지원되지 않습니다."
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -281,7 +281,6 @@
 | 
			
		||||
  "Status": "状态",
 | 
			
		||||
  "String operation": "字符串",
 | 
			
		||||
  "Submission may be withdrawn, please try refresh the list.": "提交可能已被撤回,请尝试刷新列表。",
 | 
			
		||||
  "Submit to workflow": "提交至工作流",
 | 
			
		||||
  "Submitted": "提交",
 | 
			
		||||
  "Succeed and continue": "通过并继续",
 | 
			
		||||
  "Succeeded": "成功",
 | 
			
		||||
 | 
			
		||||
@ -8,9 +8,7 @@ import LRUCache from 'lru-cache';
 | 
			
		||||
 | 
			
		||||
import initActions from './actions';
 | 
			
		||||
import { EXECUTION_STATUS } from './constants';
 | 
			
		||||
import { PluginActionTrigger } from './features/action-trigger/Plugin';
 | 
			
		||||
import { PluginAggregate } from './features/aggregate/Plugin';
 | 
			
		||||
import PluginWorkflowAPIRegularServer from './features/api-regular/plugin';
 | 
			
		||||
import PluginWorkflowApproval from './features/approval';
 | 
			
		||||
import PluginWorkflowDataMappingServer from './features/data-mapping/plugin';
 | 
			
		||||
import { PluginDelay } from './features/delay/Plugin';
 | 
			
		||||
@ -75,7 +73,6 @@ export default class PluginWorkflowServer extends Plugin {
 | 
			
		||||
    this.addFeature(PluginDynamicCalculation);
 | 
			
		||||
    this.addFeature(PluginDelay);
 | 
			
		||||
    this.addFeature(PluginAggregate);
 | 
			
		||||
    this.addFeature(PluginActionTrigger);
 | 
			
		||||
    this.addFeature(PluginWorkflowJSONParseServer);
 | 
			
		||||
    this.addFeature(PluginWorkflowJSParseServer);
 | 
			
		||||
    this.addFeature(PluginWorkflowDataMappingServer);
 | 
			
		||||
 | 
			
		||||
@ -1,156 +0,0 @@
 | 
			
		||||
import { Context as ActionContext, Next } from '@tachybase/actions';
 | 
			
		||||
import { parseCollectionName } from '@tachybase/data-source-manager';
 | 
			
		||||
import { Model, modelAssociationByKey } from '@tachybase/database';
 | 
			
		||||
import Application, { DefaultContext } from '@tachybase/server';
 | 
			
		||||
 | 
			
		||||
import { get } from 'lodash';
 | 
			
		||||
import { BelongsTo, HasOne } from 'sequelize';
 | 
			
		||||
 | 
			
		||||
import WorkflowPlugin, { toJSON, Trigger, WorkflowModel } from '../..';
 | 
			
		||||
 | 
			
		||||
interface Context extends ActionContext, DefaultContext {}
 | 
			
		||||
 | 
			
		||||
export default class extends Trigger {
 | 
			
		||||
  constructor(workflow: WorkflowPlugin) {
 | 
			
		||||
    super(workflow);
 | 
			
		||||
 | 
			
		||||
    workflow.app.use(this.middleware, { after: 'dataSource' });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async triggerAction(context: Context, next: Next) {
 | 
			
		||||
    const { triggerWorkflows } = context.action.params;
 | 
			
		||||
 | 
			
		||||
    if (!triggerWorkflows) {
 | 
			
		||||
      return context.throw(400);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    context.status = 202;
 | 
			
		||||
    await next();
 | 
			
		||||
 | 
			
		||||
    this.trigger(context);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  middleware = async (context: Context, next: Next) => {
 | 
			
		||||
    const {
 | 
			
		||||
      resourceName,
 | 
			
		||||
      actionName,
 | 
			
		||||
      params: { triggerWorkflows },
 | 
			
		||||
    } = context.action;
 | 
			
		||||
 | 
			
		||||
    if (resourceName === 'workflows' && actionName === 'trigger') {
 | 
			
		||||
      return this.triggerAction(context, next);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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: '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 = <HasOne | BelongsTo>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 } = (<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);
 | 
			
		||||
        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(workflow: WorkflowModel) {}
 | 
			
		||||
 | 
			
		||||
  off(workflow: WorkflowModel) {}
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
import { Plugin } from '@tachybase/server';
 | 
			
		||||
 | 
			
		||||
import WorkflowPlugin from '../..';
 | 
			
		||||
import ActionTrigger from './ActionTrigger';
 | 
			
		||||
 | 
			
		||||
export class PluginActionTrigger extends Plugin {
 | 
			
		||||
  async load() {
 | 
			
		||||
    const workflowPlugin = this.app.pm.get(WorkflowPlugin) as WorkflowPlugin;
 | 
			
		||||
    workflowPlugin.registerTrigger('action', new ActionTrigger(workflowPlugin));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,619 +0,0 @@
 | 
			
		||||
import Database from '@tachybase/database';
 | 
			
		||||
import { EXECUTION_STATUS } from '@tachybase/plugin-workflow';
 | 
			
		||||
import { getApp, sleep } from '@tachybase/plugin-workflow-test';
 | 
			
		||||
import { MockServer } from '@tachybase/test';
 | 
			
		||||
 | 
			
		||||
import Plugin from '..';
 | 
			
		||||
 | 
			
		||||
describe('workflow > action-trigger', () => {
 | 
			
		||||
  let app: MockServer;
 | 
			
		||||
  let db: Database;
 | 
			
		||||
  let agent;
 | 
			
		||||
  let PostRepo;
 | 
			
		||||
  let CommentRepo;
 | 
			
		||||
  let WorkflowModel;
 | 
			
		||||
  let UserRepo;
 | 
			
		||||
  let users;
 | 
			
		||||
  let userAgents;
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    app = await getApp({
 | 
			
		||||
      plugins: ['users', 'auth', Plugin],
 | 
			
		||||
    });
 | 
			
		||||
    await app.pm.get('auth').install();
 | 
			
		||||
    agent = app.agent();
 | 
			
		||||
    db = app.db;
 | 
			
		||||
    WorkflowModel = db.getCollection('workflows').model;
 | 
			
		||||
    PostRepo = db.getCollection('posts').repository;
 | 
			
		||||
    CommentRepo = db.getCollection('comments').repository;
 | 
			
		||||
    UserRepo = db.getCollection('users').repository;
 | 
			
		||||
 | 
			
		||||
    users = await UserRepo.create({
 | 
			
		||||
      values: [
 | 
			
		||||
        { id: 2, nickname: 'a', roles: [{ name: 'root' }] },
 | 
			
		||||
        { id: 3, nickname: 'b' },
 | 
			
		||||
      ],
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    userAgents = users.map((user) => app.agent().login(user));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  afterEach(() => app.destroy());
 | 
			
		||||
 | 
			
		||||
  describe('create', () => {
 | 
			
		||||
    it('enabled / disabled', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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' });
 | 
			
		||||
 | 
			
		||||
      await workflow.update({
 | 
			
		||||
        enabled: false,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res2 = await userAgents[0].resource('posts').create({
 | 
			
		||||
        values: { title: 't2' },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res2.status).toBe(200);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e2 = await workflow.getExecutions({ order: [['id', 'ASC']] });
 | 
			
		||||
      expect(e2.length).toBe(1);
 | 
			
		||||
 | 
			
		||||
      await workflow.update({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res3 = await userAgents[0].resource('posts').create({
 | 
			
		||||
        values: { title: 't3' },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res2.status).toBe(200);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e3 = await workflow.getExecutions({ order: [['id', 'ASC']] });
 | 
			
		||||
      expect(e3.length).toBe(2);
 | 
			
		||||
      expect(e3[1].status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e3[1].context.data).toMatchObject({ title: 't3' });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('only trigger if params provided matching collection config', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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' });
 | 
			
		||||
 | 
			
		||||
      await workflow.update({
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'comments',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res2 = await userAgents[0].resource('posts').create({
 | 
			
		||||
        values: { title: 't2' },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res2.status).toBe(200);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e2 = await workflow.getExecutions({ order: [['id', 'ASC']] });
 | 
			
		||||
      expect(e2.length).toBe(1);
 | 
			
		||||
      // expect(e2[1].status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      // expect(e2[1].context.data).toMatchObject({ title: 't2' });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('system fields could be accessed', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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).toHaveProperty('createdAt');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('appends', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
          appends: ['createdBy'],
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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).toHaveProperty('createdBy');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('user submitted form', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.user).toBeDefined();
 | 
			
		||||
      expect(e1.context.user.id).toBe(users[0].id);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('update', () => {
 | 
			
		||||
    it('trigger after updated', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
          appends: ['createdBy'],
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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').update({
 | 
			
		||||
        filterByTk: res1.body.data.id,
 | 
			
		||||
        values: { title: 't2' },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const [e2] = await workflow.getExecutions();
 | 
			
		||||
      expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e2.context.data).toHaveProperty('title', 't2');
 | 
			
		||||
      expect(e2.context.data).toHaveProperty('createdBy');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe.skip('destroy', () => {
 | 
			
		||||
    it('trigger after destroyed', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const p1 = await PostRepo.create({
 | 
			
		||||
        values: { title: 't1' },
 | 
			
		||||
      });
 | 
			
		||||
      const p2 = await PostRepo.create({
 | 
			
		||||
        values: { title: 't2' },
 | 
			
		||||
      });
 | 
			
		||||
      const res1 = await userAgents[0].resource('posts').destroy({
 | 
			
		||||
        filterByTk: p1.id,
 | 
			
		||||
      });
 | 
			
		||||
      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').destroy({
 | 
			
		||||
        filterByTk: p2.id,
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const [e2] = await workflow.getExecutions();
 | 
			
		||||
      expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e2.context.data).toBe(1);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('directly trigger', () => {
 | 
			
		||||
    it('no collection configured should not be triggered', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('workflows').trigger({
 | 
			
		||||
        values: { title: 't1' },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(202);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e1s = await workflow.getExecutions();
 | 
			
		||||
      expect(e1s.length).toBe(0);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('trigger on form data', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
          appends: ['createdBy'],
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.data).toMatchObject({ title: 't1' });
 | 
			
		||||
      expect(e1.context.data.createdBy).toBeUndefined();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('trigger on record data', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
          appends: ['createdBy'],
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const post = await PostRepo.create({
 | 
			
		||||
        values: { title: 't1', createdBy: users[0].id },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('workflows').trigger({
 | 
			
		||||
        values: post.toJSON(),
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(202);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const [e1] = await workflow.getExecutions();
 | 
			
		||||
      expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.data).toMatchObject({ title: 't1' });
 | 
			
		||||
      expect(e1.context.data).toHaveProperty('createdBy');
 | 
			
		||||
      expect(e1.context.data.createdBy.id).toBe(users[0].id);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('multi trigger', async () => {
 | 
			
		||||
      const w1 = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const w2 = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('workflows').trigger({
 | 
			
		||||
        values: { title: 't1' },
 | 
			
		||||
        triggerWorkflows: `${w1.key},${w2.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(202);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const [e1] = await w1.getExecutions();
 | 
			
		||||
      expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.data).toMatchObject({ title: 't1' });
 | 
			
		||||
 | 
			
		||||
      const [e2] = await w2.getExecutions();
 | 
			
		||||
      expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e2.context.data).toMatchObject({ title: 't1' });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('user submitted form', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
          appends: ['createdBy'],
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.user).toBeDefined();
 | 
			
		||||
      expect(e1.context.user.id).toBe(users[0].id);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('context data path', () => {
 | 
			
		||||
    it('level: 1', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('workflows').trigger({
 | 
			
		||||
        values: { title: 't1', category: { title: 'c1' } },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}!category`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(202);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const [e1] = await workflow.getExecutions();
 | 
			
		||||
      expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.data).toMatchObject({ title: 'c1' });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('level: 2', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('workflows').trigger({
 | 
			
		||||
        values: { content: 'comment1', post: { category: { title: 'c1' } } },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}!post.category`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(202);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const [e1] = await workflow.getExecutions();
 | 
			
		||||
      expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.data).toMatchObject({ title: 'c1' });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('workflow key', () => {
 | 
			
		||||
    it('revision', async () => {
 | 
			
		||||
      const w1 = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('workflows').trigger({
 | 
			
		||||
        values: { title: 't1' },
 | 
			
		||||
        triggerWorkflows: `${w1.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(202);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const [e1] = await w1.getExecutions();
 | 
			
		||||
      expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e1.context.data).toMatchObject({ title: 't1' });
 | 
			
		||||
 | 
			
		||||
      const res2 = await userAgents[0].resource('workflows').revision({
 | 
			
		||||
        filterByTk: w1.id,
 | 
			
		||||
        filter: {
 | 
			
		||||
          key: w1.key,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      const w2 = await WorkflowModel.findByPk(res2.body.data.id);
 | 
			
		||||
      await w2.update({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res3 = await userAgents[0].resource('workflows').trigger({
 | 
			
		||||
        values: { title: 't2' },
 | 
			
		||||
        triggerWorkflows: `${w1.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res3.status).toBe(202);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e2 = await w1.getExecutions();
 | 
			
		||||
      expect(e2.length).toBe(1);
 | 
			
		||||
      const e3 = await w2.getExecutions();
 | 
			
		||||
      expect(e3.length).toBe(1);
 | 
			
		||||
      expect(e3[0].status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
      expect(e3[0].context.data).toMatchObject({ title: 't2' });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('sync', () => {
 | 
			
		||||
    it('sync form trigger', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        sync: true,
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('posts').create({
 | 
			
		||||
        values: { title: 't1' },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(200);
 | 
			
		||||
 | 
			
		||||
      const executions = await workflow.getExecutions();
 | 
			
		||||
      expect(executions.length).toBe(1);
 | 
			
		||||
      expect(executions[0].status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sync and async will all be triggered in one action', async () => {
 | 
			
		||||
      const w1 = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const w2 = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        sync: true,
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('posts').create({
 | 
			
		||||
        values: { title: 't1' },
 | 
			
		||||
        triggerWorkflows: [w1.key, w2.key].join(),
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(200);
 | 
			
		||||
 | 
			
		||||
      const e1s = await w1.getExecutions();
 | 
			
		||||
      expect(e1s.length).toBe(0);
 | 
			
		||||
 | 
			
		||||
      const e2s = await w2.getExecutions();
 | 
			
		||||
      expect(e2s.length).toBe(1);
 | 
			
		||||
      expect(e2s[0].status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e3s = await w1.getExecutions();
 | 
			
		||||
      expect(e3s.length).toBe(1);
 | 
			
		||||
      expect(e3s[0].status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('multiple data source', () => {
 | 
			
		||||
    it('trigger on different data source', async () => {
 | 
			
		||||
      const workflow = await WorkflowModel.create({
 | 
			
		||||
        enabled: true,
 | 
			
		||||
        type: 'action',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'another:posts',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const res1 = await userAgents[0].resource('posts').create({
 | 
			
		||||
        values: { title: 't1' },
 | 
			
		||||
        triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      });
 | 
			
		||||
      expect(res1.status).toBe(200);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e1s = await workflow.getExecutions();
 | 
			
		||||
      expect(e1s.length).toBe(0);
 | 
			
		||||
 | 
			
		||||
      // const res2 = await userAgents[0]
 | 
			
		||||
      //   .set('x-data-source', 'another')
 | 
			
		||||
      //   .resource('posts')
 | 
			
		||||
      //   .create({
 | 
			
		||||
      //     values: { title: 't2' },
 | 
			
		||||
      //     triggerWorkflows: `${workflow.key}`,
 | 
			
		||||
      //   });
 | 
			
		||||
      const res2 = await agent
 | 
			
		||||
        .login(users[0])
 | 
			
		||||
        .set('x-data-source', 'another')
 | 
			
		||||
        .post('/api/posts:create')
 | 
			
		||||
        .query({ triggerWorkflows: `${workflow.key}` })
 | 
			
		||||
        .send({ title: 't2' });
 | 
			
		||||
 | 
			
		||||
      expect(res2.status).toBe(200);
 | 
			
		||||
 | 
			
		||||
      await sleep(500);
 | 
			
		||||
 | 
			
		||||
      const e2s = await workflow.getExecutions();
 | 
			
		||||
      expect(e2s.length).toBe(1);
 | 
			
		||||
      expect(e2s[0].status).toBe(EXECUTION_STATUS.RESOLVED);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user