refactor: optimize bind workflow process, move code mirrors to components and add lib to webhook (#1219)
Reviewed-on: daoyoucloud/tachybase#1219
This commit is contained in:
		
							parent
							
								
									743f0f2645
								
							
						
					
					
						commit
						6e3c2c9251
					
				@ -336,7 +336,14 @@ export function RemoveButton(
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function WorkflowSelect({ formAction, buttonAction, actionType, direct = false, ...props }) {
 | 
			
		||||
export function WorkflowSelect({
 | 
			
		||||
  formAction,
 | 
			
		||||
  buttonAction,
 | 
			
		||||
  actionType,
 | 
			
		||||
  direct = false,
 | 
			
		||||
  noCollection = false,
 | 
			
		||||
  ...props
 | 
			
		||||
}) {
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const index = ArrayTable.useIndex();
 | 
			
		||||
  const { setValuesIn } = useForm();
 | 
			
		||||
@ -417,7 +424,7 @@ export function WorkflowSelect({ formAction, buttonAction, actionType, direct =
 | 
			
		||||
            filter: {
 | 
			
		||||
              type: workflowTypes,
 | 
			
		||||
              enabled: true,
 | 
			
		||||
              'config.collection': workflowCollection,
 | 
			
		||||
              'config.collection': noCollection ? undefined : workflowCollection,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        }}
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@ant-design/cssinjs": "^1.20.0",
 | 
			
		||||
    "@ant-design/icons": "^5.3.7",
 | 
			
		||||
    "@codemirror/autocomplete": "^6.16.2",
 | 
			
		||||
    "@codemirror/lang-javascript": "^6.2.2",
 | 
			
		||||
    "@dnd-kit/core": "^6.1.0",
 | 
			
		||||
    "@dnd-kit/sortable": "^8.0.0",
 | 
			
		||||
    "@dnd-kit/utilities": "^3.2.2",
 | 
			
		||||
@ -19,6 +21,7 @@
 | 
			
		||||
    "@formily/reactive-react": "2.3.1",
 | 
			
		||||
    "@formily/shared": "2.3.1",
 | 
			
		||||
    "@formily/validator": "2.3.1",
 | 
			
		||||
    "@uiw/react-codemirror": "^4.22.2",
 | 
			
		||||
    "antd": "^5.18.1",
 | 
			
		||||
    "classnames": "^2.5.1",
 | 
			
		||||
    "dayjs": "^1.11.11",
 | 
			
		||||
 | 
			
		||||
@ -34,3 +34,4 @@ export * from './transfer';
 | 
			
		||||
export * from './tree-select';
 | 
			
		||||
export * from './upload';
 | 
			
		||||
export * from './__builtins__';
 | 
			
		||||
export * from './code-mirror';
 | 
			
		||||
 | 
			
		||||
@ -9,13 +9,10 @@
 | 
			
		||||
  "main": "dist/server/index.js",
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@ant-design/icons": "~5.3.7",
 | 
			
		||||
    "@codemirror/autocomplete": "^6.16.2",
 | 
			
		||||
    "@codemirror/lang-javascript": "^6.2.2",
 | 
			
		||||
    "@react-pdf/renderer": "^3.3.2",
 | 
			
		||||
    "@tachybase/components": "workspace:*",
 | 
			
		||||
    "@tachybase/schema": "workspace:*",
 | 
			
		||||
    "@types/lodash": "~4.17.5",
 | 
			
		||||
    "@uiw/react-codemirror": "^4.22.2",
 | 
			
		||||
    "ahooks": "^3.7.2",
 | 
			
		||||
    "antd": "5.18.1",
 | 
			
		||||
    "classnames": "^2.3.1",
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import { EditTitleField, Plugin } from '@tachybase/client';
 | 
			
		||||
import { CodeMirror } from '@tachybase/components';
 | 
			
		||||
import { autorun, isValid, useFieldSchema } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
@ -13,7 +14,6 @@ import {
 | 
			
		||||
  Expression,
 | 
			
		||||
  SignatureInput,
 | 
			
		||||
} from './components';
 | 
			
		||||
import { CodeMirror } from './components/code-mirror';
 | 
			
		||||
import { PluginAssistant } from './features/assistant';
 | 
			
		||||
import { PluginGroupBlock } from './features/block-group';
 | 
			
		||||
import { PluginContextMenu } from './features/context-menu';
 | 
			
		||||
 | 
			
		||||
@ -13,14 +13,11 @@
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@ant-design/icons": "~5.3.7",
 | 
			
		||||
    "@codemirror/autocomplete": "^6.16.2",
 | 
			
		||||
    "@codemirror/lang-javascript": "^6.2.2",
 | 
			
		||||
    "@tachybase/components": "workspace:*",
 | 
			
		||||
    "@tachybase/plugin-workflow-test": "workspace:*",
 | 
			
		||||
    "@types/ejs": "^3.1.1",
 | 
			
		||||
    "@types/file-saver": "^2.0.7",
 | 
			
		||||
    "@types/lodash": "^4.17.5",
 | 
			
		||||
    "@uiw/react-codemirror": "^4.22.2",
 | 
			
		||||
    "antd": "5.18.1",
 | 
			
		||||
    "axios": "^1.6.2",
 | 
			
		||||
    "cron-parser": "4.4.0",
 | 
			
		||||
 | 
			
		||||
@ -1,95 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { connect } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import { autocompletion } from '@codemirror/autocomplete';
 | 
			
		||||
import { javascript } from '@codemirror/lang-javascript';
 | 
			
		||||
import CM from '@uiw/react-codemirror';
 | 
			
		||||
 | 
			
		||||
// 定义全局对象和子对象的补全项
 | 
			
		||||
const globalVariables = [
 | 
			
		||||
  {
 | 
			
		||||
    label: 'ctx',
 | 
			
		||||
    type: 'variable',
 | 
			
		||||
    info: 'Global context object',
 | 
			
		||||
    apply: (view, completion, from, to) => {
 | 
			
		||||
      view.dispatch({
 | 
			
		||||
        changes: { from, to, insert: completion.label },
 | 
			
		||||
        selection: { anchor: from + completion.label.length },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const ctxProperties = [
 | 
			
		||||
  { label: 'body', type: 'variable', info: 'pass to workflow or response to user' },
 | 
			
		||||
  { label: 'request', type: 'variable', info: 'ctx.request' },
 | 
			
		||||
  { label: 'action', type: 'variable', info: 'ctx.action' },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const requestProperties = [
 | 
			
		||||
  { label: 'header', type: 'variable', info: 'ctx.request.header' },
 | 
			
		||||
  { label: 'query', type: 'variable', info: 'ctx.request.query' },
 | 
			
		||||
  { label: 'body', type: 'variable', info: 'ctx.request.body' },
 | 
			
		||||
  { label: 'method', type: 'variable', info: 'ctx.request.method' },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const actionProperties = [
 | 
			
		||||
  { label: 'filter', type: 'variable', info: 'ctx.action.filter' },
 | 
			
		||||
  { label: 'fields', type: 'variable', info: 'ctx.action.fields' },
 | 
			
		||||
  { label: 'except', type: 'variable', info: 'ctx.action.except' },
 | 
			
		||||
  { label: 'appends', type: 'variable', info: 'ctx.action.appends' },
 | 
			
		||||
  { label: 'sort', type: 'variable', info: 'ctx.action.sort' },
 | 
			
		||||
  { label: 'paginate', type: 'variable', info: 'ctx.action.paginate' },
 | 
			
		||||
  { label: 'page', type: 'variable', info: 'ctx.action.page' },
 | 
			
		||||
  { label: 'pageSize', type: 'variable', info: 'ctx.action.pageSize' },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const completionSource = (context) => {
 | 
			
		||||
  const word = context.matchBefore(/\w*/);
 | 
			
		||||
  if (word.from === word.to && !context.explicit) return null;
 | 
			
		||||
 | 
			
		||||
  if (context.state.sliceDoc(word.from - 4, word.from) === 'ctx.') {
 | 
			
		||||
    return {
 | 
			
		||||
      from: word.from,
 | 
			
		||||
      options: ctxProperties,
 | 
			
		||||
      validFor: /^\w*$/,
 | 
			
		||||
    };
 | 
			
		||||
  } else if (context.state.sliceDoc(word.from - 8, word.from) === 'ctx.request.') {
 | 
			
		||||
    return {
 | 
			
		||||
      from: word.from,
 | 
			
		||||
      options: requestProperties,
 | 
			
		||||
      validFor: /^\w*$/,
 | 
			
		||||
    };
 | 
			
		||||
  } else if (context.state.sliceDoc(word.from - 7, word.from) === 'ctx.action.') {
 | 
			
		||||
    return {
 | 
			
		||||
      from: word.from,
 | 
			
		||||
      options: actionProperties,
 | 
			
		||||
      validFor: /^\w*$/,
 | 
			
		||||
    };
 | 
			
		||||
  } else if (context.explicit && word.text.length === 0) {
 | 
			
		||||
    return {
 | 
			
		||||
      from: word.from,
 | 
			
		||||
      options: globalVariables,
 | 
			
		||||
      validFor: /^\w*$/,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const CodeMirror = connect(({ value, onChange, ...otherProps }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <CM
 | 
			
		||||
      value={value || ''}
 | 
			
		||||
      onChange={onChange}
 | 
			
		||||
      {...otherProps}
 | 
			
		||||
      extensions={[
 | 
			
		||||
        javascript({ jsx: true }),
 | 
			
		||||
        autocompletion({
 | 
			
		||||
          override: [completionSource],
 | 
			
		||||
        }),
 | 
			
		||||
      ]}
 | 
			
		||||
      height="300px"
 | 
			
		||||
    ></CM>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -12,34 +12,27 @@ export class OmniActionTrigger extends Trigger {
 | 
			
		||||
    `Omni Trigger is a versatile trigger. You can use it to trigger workflows in a table, trigger it from another workflow, or trigger it with a form button.`,
 | 
			
		||||
  );
 | 
			
		||||
  fieldset = {
 | 
			
		||||
    bindCollection: {
 | 
			
		||||
      type: 'boolean',
 | 
			
		||||
      title: tval('Bind collection?'),
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'Radio.Group',
 | 
			
		||||
      enum: [
 | 
			
		||||
        { label: tval('Yes'), value: true },
 | 
			
		||||
        { label: tval('No'), value: false },
 | 
			
		||||
      ],
 | 
			
		||||
      required: true,
 | 
			
		||||
      default: false,
 | 
			
		||||
    },
 | 
			
		||||
    collection: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: tval('Collection'),
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'DataSourceCollectionCascader',
 | 
			
		||||
      'x-reactions': [{ target: 'changed', effects: ['onFieldValueChange'], fulfill: { state: { value: [] } } }],
 | 
			
		||||
    },
 | 
			
		||||
    isWebhook: {
 | 
			
		||||
      type: 'boolean',
 | 
			
		||||
      title: tval('is webhook'),
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'Radio.Group',
 | 
			
		||||
      enum: [
 | 
			
		||||
        { label: tval('No'), value: false },
 | 
			
		||||
        { label: tval('Yes'), value: true },
 | 
			
		||||
      ],
 | 
			
		||||
      required: true,
 | 
			
		||||
      default: false,
 | 
			
		||||
      'x-reactions': [
 | 
			
		||||
        {
 | 
			
		||||
          target: 'collection',
 | 
			
		||||
          effects: ['onFieldValueChange'],
 | 
			
		||||
          fulfill: {
 | 
			
		||||
            state: {
 | 
			
		||||
              value: 'webhooks',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        { target: 'changed', effects: ['onFieldValueChange'], fulfill: { state: { value: [] } } },
 | 
			
		||||
        { dependencies: ['bindCollection'], fulfill: { state: { visible: '{{!!$deps[0]}}' } } },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
    appends: {
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { ExtendCollectionsProvider, SchemaComponent, WorkflowSelect } from '@tachybase/client';
 | 
			
		||||
import { CollectionOptions, ExtendCollectionsProvider, SchemaComponent, WorkflowSelect } from '@tachybase/client';
 | 
			
		||||
import { CodeMirror } from '@tachybase/components';
 | 
			
		||||
import { ISchema } from '@tachybase/schema';
 | 
			
		||||
 | 
			
		||||
import { CodeMirror } from '../../components/code-mirror';
 | 
			
		||||
import { tval } from '../../locale';
 | 
			
		||||
 | 
			
		||||
const collection = {
 | 
			
		||||
export const collection: CollectionOptions = {
 | 
			
		||||
  name: 'webhooks',
 | 
			
		||||
  title: 'webhooks',
 | 
			
		||||
  fields: [
 | 
			
		||||
@ -46,6 +46,7 @@ const collection = {
 | 
			
		||||
        'x-component': 'WorkflowSelect',
 | 
			
		||||
        'x-component-props': {
 | 
			
		||||
          buttonAction: 'customize:triggerWorkflows',
 | 
			
		||||
          noCollection: true,
 | 
			
		||||
          label: 'title',
 | 
			
		||||
          value: 'key',
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@ -4,12 +4,12 @@ import { useTranslation } from 'react-i18next';
 | 
			
		||||
export const NAMESPACE = 'workflow';
 | 
			
		||||
 | 
			
		||||
export function lang(key: string, options = {}) {
 | 
			
		||||
  return i18n.t(key, { ...options, ns: NAMESPACE });
 | 
			
		||||
  return i18n.t(key, { ...options, ns: [NAMESPACE, 'client'] });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useWorkflowTranslation() {
 | 
			
		||||
  return useTranslation(NAMESPACE);
 | 
			
		||||
  return useTranslation([NAMESPACE, 'client']);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const tval = (key: string, opts={}) => nTval(key, { ns: NAMESPACE, ...opts });
 | 
			
		||||
export const tval = (key: string, opts={}) => nTval(key, { ns: [NAMESPACE, 'client'], ...opts });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,7 @@
 | 
			
		||||
  "Associations to use": "Associations to use",
 | 
			
		||||
  "Based on certain date": "Based on certain date",
 | 
			
		||||
  "Based on date field of collection": "Based on date field of collection",
 | 
			
		||||
  "Bind collection?": "Bind collection?",
 | 
			
		||||
  "Body": "Body",
 | 
			
		||||
  "Boolean": "Boolean",
 | 
			
		||||
  "Branch into \"Yes\" and \"No\"": "Branch into \"Yes\" and \"No\"",
 | 
			
		||||
 | 
			
		||||
@ -56,6 +56,7 @@
 | 
			
		||||
  "Based on certain date": "自定义时间",
 | 
			
		||||
  "Based on date field of collection": "根据数据表时间字段",
 | 
			
		||||
  "Basic": "基础",
 | 
			
		||||
  "Bind collection?": "绑定数据集?",
 | 
			
		||||
  "Bind workflows": "绑定工作流",
 | 
			
		||||
  "Body": "请求体",
 | 
			
		||||
  "Branch into \"Yes\" and \"No\"": "“是”和“否”分别继续",
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import { Context } from '@tachybase/actions';
 | 
			
		||||
import { PluginWorkflow } from '@tachybase/plugin-workflow';
 | 
			
		||||
import { dayjs } from '@tachybase/utils';
 | 
			
		||||
 | 
			
		||||
export class WebhookController {
 | 
			
		||||
  async getLink(ctx: Context) {
 | 
			
		||||
@ -27,6 +28,11 @@ export class WebhookController {
 | 
			
		||||
    };
 | 
			
		||||
    run(webhook.code, {
 | 
			
		||||
      ctx: webhookCtx,
 | 
			
		||||
      lib: {
 | 
			
		||||
        JSON,
 | 
			
		||||
        Math,
 | 
			
		||||
        dayjs,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    if (webhook?.workflowKey) {
 | 
			
		||||
      const wfRepo = ctx.db.getRepository('workflows');
 | 
			
		||||
@ -48,9 +54,9 @@ export class WebhookController {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function run(jsCode: string, { ctx }) {
 | 
			
		||||
function run(jsCode: string, { ctx, lib }) {
 | 
			
		||||
  try {
 | 
			
		||||
    return new Function('$root', `with($root) { ${jsCode}; }`)({ ctx });
 | 
			
		||||
    return new Function('$root', `with($root) { ${jsCode}; }`)({ ctx, lib });
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    console.log('err', err);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2174
									
								
								pnpm-lock.yaml
									
									
									
									
									
								
							
							
						
						
									
										2174
									
								
								pnpm-lock.yaml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user