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 { t } = useTranslation();
|
||||||
const index = ArrayTable.useIndex();
|
const index = ArrayTable.useIndex();
|
||||||
const { setValuesIn } = useForm();
|
const { setValuesIn } = useForm();
|
||||||
@ -417,7 +424,7 @@ export function WorkflowSelect({ formAction, buttonAction, actionType, direct =
|
|||||||
filter: {
|
filter: {
|
||||||
type: workflowTypes,
|
type: workflowTypes,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
'config.collection': workflowCollection,
|
'config.collection': noCollection ? undefined : workflowCollection,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/cssinjs": "^1.20.0",
|
"@ant-design/cssinjs": "^1.20.0",
|
||||||
"@ant-design/icons": "^5.3.7",
|
"@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/core": "^6.1.0",
|
||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
@ -19,6 +21,7 @@
|
|||||||
"@formily/reactive-react": "2.3.1",
|
"@formily/reactive-react": "2.3.1",
|
||||||
"@formily/shared": "2.3.1",
|
"@formily/shared": "2.3.1",
|
||||||
"@formily/validator": "2.3.1",
|
"@formily/validator": "2.3.1",
|
||||||
|
"@uiw/react-codemirror": "^4.22.2",
|
||||||
"antd": "^5.18.1",
|
"antd": "^5.18.1",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
|
@ -34,3 +34,4 @@ export * from './transfer';
|
|||||||
export * from './tree-select';
|
export * from './tree-select';
|
||||||
export * from './upload';
|
export * from './upload';
|
||||||
export * from './__builtins__';
|
export * from './__builtins__';
|
||||||
|
export * from './code-mirror';
|
||||||
|
@ -9,13 +9,10 @@
|
|||||||
"main": "dist/server/index.js",
|
"main": "dist/server/index.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ant-design/icons": "~5.3.7",
|
"@ant-design/icons": "~5.3.7",
|
||||||
"@codemirror/autocomplete": "^6.16.2",
|
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
|
||||||
"@react-pdf/renderer": "^3.3.2",
|
"@react-pdf/renderer": "^3.3.2",
|
||||||
"@tachybase/components": "workspace:*",
|
"@tachybase/components": "workspace:*",
|
||||||
"@tachybase/schema": "workspace:*",
|
"@tachybase/schema": "workspace:*",
|
||||||
"@types/lodash": "~4.17.5",
|
"@types/lodash": "~4.17.5",
|
||||||
"@uiw/react-codemirror": "^4.22.2",
|
|
||||||
"ahooks": "^3.7.2",
|
"ahooks": "^3.7.2",
|
||||||
"antd": "5.18.1",
|
"antd": "5.18.1",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { EditTitleField, Plugin } from '@tachybase/client';
|
import { EditTitleField, Plugin } from '@tachybase/client';
|
||||||
|
import { CodeMirror } from '@tachybase/components';
|
||||||
import { autorun, isValid, useFieldSchema } from '@tachybase/schema';
|
import { autorun, isValid, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -13,7 +14,6 @@ import {
|
|||||||
Expression,
|
Expression,
|
||||||
SignatureInput,
|
SignatureInput,
|
||||||
} from './components';
|
} from './components';
|
||||||
import { CodeMirror } from './components/code-mirror';
|
|
||||||
import { PluginAssistant } from './features/assistant';
|
import { PluginAssistant } from './features/assistant';
|
||||||
import { PluginGroupBlock } from './features/block-group';
|
import { PluginGroupBlock } from './features/block-group';
|
||||||
import { PluginContextMenu } from './features/context-menu';
|
import { PluginContextMenu } from './features/context-menu';
|
||||||
|
@ -13,14 +13,11 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ant-design/icons": "~5.3.7",
|
"@ant-design/icons": "~5.3.7",
|
||||||
"@codemirror/autocomplete": "^6.16.2",
|
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
|
||||||
"@tachybase/components": "workspace:*",
|
"@tachybase/components": "workspace:*",
|
||||||
"@tachybase/plugin-workflow-test": "workspace:*",
|
"@tachybase/plugin-workflow-test": "workspace:*",
|
||||||
"@types/ejs": "^3.1.1",
|
"@types/ejs": "^3.1.1",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/lodash": "^4.17.5",
|
"@types/lodash": "^4.17.5",
|
||||||
"@uiw/react-codemirror": "^4.22.2",
|
|
||||||
"antd": "5.18.1",
|
"antd": "5.18.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"cron-parser": "4.4.0",
|
"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.`,
|
`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 = {
|
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: {
|
collection: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
title: tval('Collection'),
|
title: tval('Collection'),
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'DataSourceCollectionCascader',
|
'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,
|
required: true,
|
||||||
default: false,
|
|
||||||
'x-reactions': [
|
'x-reactions': [
|
||||||
{
|
{ target: 'changed', effects: ['onFieldValueChange'], fulfill: { state: { value: [] } } },
|
||||||
target: 'collection',
|
{ dependencies: ['bindCollection'], fulfill: { state: { visible: '{{!!$deps[0]}}' } } },
|
||||||
effects: ['onFieldValueChange'],
|
|
||||||
fulfill: {
|
|
||||||
state: {
|
|
||||||
value: 'webhooks',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
appends: {
|
appends: {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from 'react';
|
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 { ISchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { CodeMirror } from '../../components/code-mirror';
|
|
||||||
import { tval } from '../../locale';
|
import { tval } from '../../locale';
|
||||||
|
|
||||||
const collection = {
|
export const collection: CollectionOptions = {
|
||||||
name: 'webhooks',
|
name: 'webhooks',
|
||||||
title: 'webhooks',
|
title: 'webhooks',
|
||||||
fields: [
|
fields: [
|
||||||
@ -46,6 +46,7 @@ const collection = {
|
|||||||
'x-component': 'WorkflowSelect',
|
'x-component': 'WorkflowSelect',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
buttonAction: 'customize:triggerWorkflows',
|
buttonAction: 'customize:triggerWorkflows',
|
||||||
|
noCollection: true,
|
||||||
label: 'title',
|
label: 'title',
|
||||||
value: 'key',
|
value: 'key',
|
||||||
},
|
},
|
||||||
|
@ -4,12 +4,12 @@ import { useTranslation } from 'react-i18next';
|
|||||||
export const NAMESPACE = 'workflow';
|
export const NAMESPACE = 'workflow';
|
||||||
|
|
||||||
export function lang(key: string, options = {}) {
|
export function lang(key: string, options = {}) {
|
||||||
return i18n.t(key, { ...options, ns: NAMESPACE });
|
return i18n.t(key, { ...options, ns: [NAMESPACE, 'client'] });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useWorkflowTranslation() {
|
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",
|
"Associations to use": "Associations to use",
|
||||||
"Based on certain date": "Based on certain date",
|
"Based on certain date": "Based on certain date",
|
||||||
"Based on date field of collection": "Based on date field of collection",
|
"Based on date field of collection": "Based on date field of collection",
|
||||||
|
"Bind collection?": "Bind collection?",
|
||||||
"Body": "Body",
|
"Body": "Body",
|
||||||
"Boolean": "Boolean",
|
"Boolean": "Boolean",
|
||||||
"Branch into \"Yes\" and \"No\"": "Branch into \"Yes\" and \"No\"",
|
"Branch into \"Yes\" and \"No\"": "Branch into \"Yes\" and \"No\"",
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
"Based on certain date": "自定义时间",
|
"Based on certain date": "自定义时间",
|
||||||
"Based on date field of collection": "根据数据表时间字段",
|
"Based on date field of collection": "根据数据表时间字段",
|
||||||
"Basic": "基础",
|
"Basic": "基础",
|
||||||
|
"Bind collection?": "绑定数据集?",
|
||||||
"Bind workflows": "绑定工作流",
|
"Bind workflows": "绑定工作流",
|
||||||
"Body": "请求体",
|
"Body": "请求体",
|
||||||
"Branch into \"Yes\" and \"No\"": "“是”和“否”分别继续",
|
"Branch into \"Yes\" and \"No\"": "“是”和“否”分别继续",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Context } from '@tachybase/actions';
|
import { Context } from '@tachybase/actions';
|
||||||
import { PluginWorkflow } from '@tachybase/plugin-workflow';
|
import { PluginWorkflow } from '@tachybase/plugin-workflow';
|
||||||
|
import { dayjs } from '@tachybase/utils';
|
||||||
|
|
||||||
export class WebhookController {
|
export class WebhookController {
|
||||||
async getLink(ctx: Context) {
|
async getLink(ctx: Context) {
|
||||||
@ -27,6 +28,11 @@ export class WebhookController {
|
|||||||
};
|
};
|
||||||
run(webhook.code, {
|
run(webhook.code, {
|
||||||
ctx: webhookCtx,
|
ctx: webhookCtx,
|
||||||
|
lib: {
|
||||||
|
JSON,
|
||||||
|
Math,
|
||||||
|
dayjs,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if (webhook?.workflowKey) {
|
if (webhook?.workflowKey) {
|
||||||
const wfRepo = ctx.db.getRepository('workflows');
|
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 {
|
try {
|
||||||
return new Function('$root', `with($root) { ${jsCode}; }`)({ ctx });
|
return new Function('$root', `with($root) { ${jsCode}; }`)({ ctx, lib });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err', 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