fix(plugin-workflow): fix trigger getter (#1060)
This commit is contained in:
		
							parent
							
								
									2aa4468763
								
							
						
					
					
						commit
						1bd3e93588
					
				@ -540,6 +540,9 @@ export default {
 | 
			
		||||
  'Load failed': '加载失败',
 | 
			
		||||
 | 
			
		||||
  'Trigger': '触发器',
 | 
			
		||||
  'Trigger context': '触发数据',
 | 
			
		||||
  'Trigger data': '触发数据',
 | 
			
		||||
  'Trigger time': '触发时间',
 | 
			
		||||
  'Triggered at': '触发时间',
 | 
			
		||||
  'Collection event': '数据表事件',
 | 
			
		||||
  'Trigger on': '触发时机',
 | 
			
		||||
@ -585,7 +588,6 @@ export default {
 | 
			
		||||
 | 
			
		||||
  'End': '结束',
 | 
			
		||||
 | 
			
		||||
  'Trigger context': '触发数据',
 | 
			
		||||
  'Node result': '节点数据',
 | 
			
		||||
  'Constant': '常量',
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
 | 
			
		||||
import { Calculation } from '../calculators';
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,20 @@ const FieldsSelect = observer((props) => {
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const COLLECTION_TRIGGER_MODE = {
 | 
			
		||||
  CREATED: 1,
 | 
			
		||||
  UPDATED: 2,
 | 
			
		||||
  SAVED: 3,
 | 
			
		||||
  DELETED: 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const collectionModeOptions = [
 | 
			
		||||
  { label: '{{t("After record added")}}', value: COLLECTION_TRIGGER_MODE.CREATED },
 | 
			
		||||
  { label: '{{t("After record updated")}}', value: COLLECTION_TRIGGER_MODE.UPDATED },
 | 
			
		||||
  { label: '{{t("After record added or updated")}}', value: COLLECTION_TRIGGER_MODE.SAVED },
 | 
			
		||||
  { label: '{{t("After record deleted")}}', value: COLLECTION_TRIGGER_MODE.DELETED },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
@ -85,12 +99,7 @@ export default {
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'Select',
 | 
			
		||||
      'x-component-props': {
 | 
			
		||||
        options: [
 | 
			
		||||
          { value: 1, label: '{{t("After record added")}}' },
 | 
			
		||||
          { value: 2, label: '{{t("After record updated")}}' },
 | 
			
		||||
          { value: 3, label: '{{t("After record added or updated")}}' },
 | 
			
		||||
          { value: 4, label: '{{t("After record deleted")}}' }
 | 
			
		||||
        ],
 | 
			
		||||
        options: collectionModeOptions,
 | 
			
		||||
        placeholder: '{{t("Trigger on")}}'
 | 
			
		||||
      },
 | 
			
		||||
      required: true,
 | 
			
		||||
@ -99,7 +108,7 @@ export default {
 | 
			
		||||
          target: 'config.changed',
 | 
			
		||||
          fulfill: {
 | 
			
		||||
            state: {
 | 
			
		||||
              disabled: '{{!($self.value & 0b010)}}',
 | 
			
		||||
              disabled: `{{!($self.value & ${COLLECTION_TRIGGER_MODE.UPDATED})}}`,
 | 
			
		||||
            },
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@ -9,9 +9,10 @@ import { collection } from '../../schemas/collection';
 | 
			
		||||
import { OnField } from './OnField';
 | 
			
		||||
import { EndsByField } from './EndsByField';
 | 
			
		||||
import { RepeatField } from './RepeatField';
 | 
			
		||||
import { SCHEDULE_MODE } from './constants';
 | 
			
		||||
 | 
			
		||||
const ModeFieldsets = {
 | 
			
		||||
  0: {
 | 
			
		||||
  [SCHEDULE_MODE.STATIC]: {
 | 
			
		||||
    startsOn: {
 | 
			
		||||
      type: 'datetime',
 | 
			
		||||
      name: 'startsOn',
 | 
			
		||||
@ -70,7 +71,7 @@ const ModeFieldsets = {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  1: {
 | 
			
		||||
  [SCHEDULE_MODE.COLLECTION_FIELD]: {
 | 
			
		||||
    collection: {
 | 
			
		||||
      ...collection,
 | 
			
		||||
      'x-reactions': [
 | 
			
		||||
@ -148,6 +149,11 @@ const ModeFieldsets = {
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const scheduleModeOptions = [
 | 
			
		||||
  { value: SCHEDULE_MODE.STATIC, label: '{{t("Based on certain date")}}' },
 | 
			
		||||
  { value: SCHEDULE_MODE.COLLECTION_FIELD, label: '{{t("Based on date field of collection")}}' },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const ScheduleConfig = () => {
 | 
			
		||||
  const { values = {}, clearFormGraph } = useForm();
 | 
			
		||||
  const { config = {} } = values;
 | 
			
		||||
@ -173,10 +179,7 @@ export const ScheduleConfig = () => {
 | 
			
		||||
          'x-decorator': 'FormItem',
 | 
			
		||||
          'x-component': 'Radio.Group',
 | 
			
		||||
          'x-component-props': {
 | 
			
		||||
            options: [
 | 
			
		||||
              { value: 0, label: '{{t("Based on certain date")}}' },
 | 
			
		||||
              { value: 1, label: '{{t("Based on date field of collection")}}' },
 | 
			
		||||
            ]
 | 
			
		||||
            options: scheduleModeOptions
 | 
			
		||||
          },
 | 
			
		||||
          required: true
 | 
			
		||||
        }}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,4 @@
 | 
			
		||||
export const SCHEDULE_MODE = {
 | 
			
		||||
  STATIC: 0,
 | 
			
		||||
  COLLECTION_FIELD: 1
 | 
			
		||||
};
 | 
			
		||||
@ -1,12 +1,14 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Select } from 'antd';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { Cascader } from 'antd';
 | 
			
		||||
 | 
			
		||||
import { useCompile, useCollectionDataSource, useCollectionManager } from '@nocobase/client';
 | 
			
		||||
 | 
			
		||||
import { ScheduleConfig } from './ScheduleConfig';
 | 
			
		||||
import { useFlowContext } from '../../FlowContext';
 | 
			
		||||
import { BaseTypeSet } from '../../calculators';
 | 
			
		||||
import { SCHEDULE_MODE } from './constants';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  title: '{{t("Schedule event")}}',
 | 
			
		||||
@ -29,24 +31,35 @@ export default {
 | 
			
		||||
  getter({ type, options, onChange }) {
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const compile = useCompile();
 | 
			
		||||
    const { collections = [] } = useCollectionManager();
 | 
			
		||||
    const { workflow } = useFlowContext();
 | 
			
		||||
    const { collections = [] } = useCollectionManager();
 | 
			
		||||
    const path = options?.path ? options.path.split('.') : [];
 | 
			
		||||
    const varOptions: any[] = [
 | 
			
		||||
      { value: 'date', label: t('Trigger time') },
 | 
			
		||||
    ];
 | 
			
		||||
    if (workflow.config.mode === SCHEDULE_MODE.COLLECTION_FIELD) {
 | 
			
		||||
      const collection = collections.find(item => item.name === workflow.config.collection) ?? { fields: [] };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <Select
 | 
			
		||||
        placeholder={t('Fields')}
 | 
			
		||||
        value={options?.path?.replace(/^data\./, '')}
 | 
			
		||||
        onChange={(path) => {
 | 
			
		||||
          onChange({ type, options: { ...options, path: `data.${path}` } });
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        {collection.fields
 | 
			
		||||
      varOptions.push({
 | 
			
		||||
        value: 'data',
 | 
			
		||||
        label: t('Trigger data'),
 | 
			
		||||
        children: collection.fields
 | 
			
		||||
          .filter(field => BaseTypeSet.has(field?.uiSchema?.type))
 | 
			
		||||
          .map(field => (
 | 
			
		||||
          <Select.Option key={field.name} value={field.name}>{compile(field.uiSchema.title)}</Select.Option>
 | 
			
		||||
        ))}
 | 
			
		||||
      </Select>
 | 
			
		||||
          .map(field => ({
 | 
			
		||||
            value: field.name,
 | 
			
		||||
            label: compile(field.uiSchema?.title),
 | 
			
		||||
          }))
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
      <Cascader
 | 
			
		||||
        placeholder={t('Trigger context')}
 | 
			
		||||
        value={path}
 | 
			
		||||
        options={varOptions}
 | 
			
		||||
        onChange={(next) => {
 | 
			
		||||
          onChange({ type, options: { ...options, path: next.join('.') } });
 | 
			
		||||
        }}
 | 
			
		||||
        allowClear={false}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -156,7 +156,7 @@ export default class WorkflowPlugin extends Plugin {
 | 
			
		||||
      key: workflow.key,
 | 
			
		||||
      status: EXECUTION_STATUS.STARTED,
 | 
			
		||||
      useTransaction: workflow.useTransaction,
 | 
			
		||||
      transaction: transaction.id
 | 
			
		||||
      transaction: transaction?.id
 | 
			
		||||
    }, { transaction });
 | 
			
		||||
 | 
			
		||||
    console.log('workflow triggered:', new Date(), workflow.id, execution.id);
 | 
			
		||||
 | 
			
		||||
@ -79,6 +79,44 @@ describe('workflow > instructions > delay', () => {
 | 
			
		||||
      const [j2] = await e2.getJobs();
 | 
			
		||||
      expect(j2.status).toBe(JOB_STATUS.REJECTED);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('delay to resolve and rollback in downstream node', async () => {
 | 
			
		||||
      const n1 = await workflow.createNode({
 | 
			
		||||
        type: 'delay',
 | 
			
		||||
        config: {
 | 
			
		||||
          duration: 1000,
 | 
			
		||||
          endStatus: JOB_STATUS.RESOLVED
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      const n2 = await workflow.createNode({
 | 
			
		||||
        type: 'create',
 | 
			
		||||
        config: {
 | 
			
		||||
          collection: 'comment',
 | 
			
		||||
          params: {
 | 
			
		||||
            values: {
 | 
			
		||||
              status: 'should be number but use string to raise an error'
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        upstreamId: n1.id
 | 
			
		||||
      });
 | 
			
		||||
      await n1.setDownstream(n2);
 | 
			
		||||
 | 
			
		||||
      const post = await PostRepo.create({ values: { title: 't1' } });
 | 
			
		||||
 | 
			
		||||
      const [e1] = await workflow.getExecutions();
 | 
			
		||||
      expect(e1.status).toEqual(EXECUTION_STATUS.STARTED);
 | 
			
		||||
      const [j1] = await e1.getJobs();
 | 
			
		||||
      expect(j1.status).toBe(JOB_STATUS.PENDING);
 | 
			
		||||
 | 
			
		||||
      await sleep(2000);
 | 
			
		||||
 | 
			
		||||
      const [e2] = await workflow.getExecutions();
 | 
			
		||||
      expect(e2.status).toEqual(EXECUTION_STATUS.REJECTED);
 | 
			
		||||
      const [j2, j3] = await e2.getJobs({ order: [['id', 'ASC']] });
 | 
			
		||||
      expect(j2.status).toBe(JOB_STATUS.RESOLVED);
 | 
			
		||||
      expect(j3.status).toBe(JOB_STATUS.REJECTED);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('app lifecycle', () => {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user