mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 08:55:33 +00:00
feat(plugin-workflow): add node description to drawer when edit node (#1882)
* feat(plugin-workflow): add node description to drawer when edit node * fix(plugin-workflow): fix manual description * fix(plugin-workflow): fix languages
This commit is contained in:
parent
e0646650f0
commit
2060bd4d44
@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { Tag } from 'antd';
|
||||
import { lang } from '../locale';
|
||||
|
||||
export function NodeDescription(props) {
|
||||
const { instruction } = props;
|
||||
const className = css`
|
||||
margin-bottom: 1.5em;
|
||||
padding: 1em;
|
||||
background: #f6f6f6;
|
||||
|
||||
> *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dl {
|
||||
display: flex;
|
||||
|
||||
dt {
|
||||
&:after {
|
||||
content: ':';
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<div className={cx(className, props.className)}>
|
||||
<dl>
|
||||
<dt>{lang('Node type')}</dt>
|
||||
<dd>
|
||||
<Tag>{instruction.title}</Tag>
|
||||
</dd>
|
||||
</dl>
|
||||
{instruction.description ? <p>{instruction.description}</p> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
export { triggers } from './triggers';
|
||||
export * from './nodes';
|
||||
export * from './FlowContext';
|
||||
export * from './Branch';
|
||||
export { WorkflowProvider as default } from './WorkflowProvider';
|
||||
|
@ -28,7 +28,8 @@ export default {
|
||||
'只有被选中的某个字段发生变动时才会触发。如果不选择,则表示任何字段变动时都会触发。新增或删除数据时,任意字段都被认为发生变动。',
|
||||
'Only triggers when match conditions': '满足以下条件才触发',
|
||||
'Preload associations': '预加载关联数据',
|
||||
'Only configured association field could be accessed in following nodes': '仅已配置的关系数据可以在后续节点中被访问',
|
||||
'Please select the associated fields that need to be accessed in subsequent nodes':
|
||||
'请选中需要在后续节点中被访问的关系字段',
|
||||
'Schedule event': '定时任务',
|
||||
'Trigger mode': '触发模式',
|
||||
'Based on certain date': '自定义时间',
|
||||
@ -59,7 +60,8 @@ export default {
|
||||
End: '结束',
|
||||
'Node result': '节点数据',
|
||||
Calculator: '运算',
|
||||
'Arithmetic calculation': '算术运算',
|
||||
'Calculate an expression based on a calculation engine and obtain a value as the result. Variables in the upstream nodes can be used in the expression. The expression can be static or dynamic one from an expression collections.':
|
||||
'基于计算引擎对一个表达式进行计算,并获得一个值作为结果。表达式中可以使用上游节点里的变量。表达式可以是静态的,也可以是表达式表中的动态表达式。',
|
||||
'String operation': '字符串',
|
||||
'System variables': '系统变量',
|
||||
'System time': '系统时间',
|
||||
@ -86,6 +88,8 @@ export default {
|
||||
Control: '流程控制',
|
||||
'Collection operations': '数据表操作',
|
||||
Manual: '人工处理',
|
||||
'Could be used for manually submitting data, and determine whether to continue or exit. Workflow will generate a todo item for assigned user when it reaches a manual node, and continue processing after user submits the form.':
|
||||
'可用于人工提交数据,并决定是否继续或退出流程。工作流在执行到人工节点时会为被指派的用户生成待办事项,直到用户提交对应表单后继续处理该流程。',
|
||||
'Extended types': '扩展类型',
|
||||
'Node type': '节点类型',
|
||||
Calculation: '运算',
|
||||
@ -93,6 +97,8 @@ export default {
|
||||
Static: '静态',
|
||||
Dynamic: '动态',
|
||||
'Select dynamic expression': '选择动态表达式',
|
||||
'Select the dynamic expression queried from the upstream node. You need to query it from an expression collection.':
|
||||
'从上游节点中选择查询出来的动态表达式。你需要从动态表达式类型的数据表中查询。',
|
||||
'Variable datasource': '变量数据源',
|
||||
'Calculation engine': '运算引擎',
|
||||
Basic: '基础',
|
||||
@ -104,28 +110,34 @@ export default {
|
||||
False: '假',
|
||||
concat: '连接',
|
||||
Condition: '条件判断',
|
||||
'Based on boolean result of the calculation to determine whether to "continue" or "exit" the process, or continue on different branches of "yes" and "no".':
|
||||
'基于运算结果的真假来决定“继续”或“退出”流程,或者在“是”与“否”的分支上分别继续。',
|
||||
Mode: '模式',
|
||||
'Continue when "Yes"': '“是”则继续',
|
||||
'Branch into "Yes" and "No"': '“是”和“否”分别继续',
|
||||
'Condition expression': '条件表达式',
|
||||
'Parallel branch': '分支',
|
||||
'Run multiple branch processes in parallel.': '并行运行多个分支流程。',
|
||||
'Add branch': '增加分支',
|
||||
'All succeeded': '全部成功',
|
||||
'Any succeeded': '任意成功',
|
||||
'Any succeeded or failed': '任意成功或失败',
|
||||
'Continue after all branches succeeded': '全部分支都成功后才能继续',
|
||||
'Continue after any branch succeeded': '任意分支成功后就继续',
|
||||
'Continue after any branch succeeded, or exit after any branch failed': '任意分支成功继续,或失败后退出',
|
||||
'Continue after any branch succeeded, or exit after any branch failed.':
|
||||
'任意分支成功就继续流程,或者任意分支失败就退出流程。',
|
||||
Loop: '循环',
|
||||
'Loop target': '循环对象',
|
||||
'Loop index': '当前索引',
|
||||
'Loop length': '循环长度',
|
||||
'Loop will cause performance issue based on the quantity, please use with caution.':
|
||||
'循环次数过高可能引起性能问题,请谨慎使用。',
|
||||
'By using a loop node, you can perform the same operation on multiple sets of data. The source of these sets can be either multiple records from a query node or multiple associated records of a single record. Loop node can also be used for iterating a certain number of times or for looping through each character in a string. However, excessive looping may cause performance issues, so use with caution.':
|
||||
'使用循环节点可以对多条数据进行同样的操作,多条数据的来源可以是查询节点的多条结果,或者一条数据的多条关系数据。也可以用于一定次数的循环,或者对字符串中每一个字符的循环处理。循环次数过高可能引起性能问题,请谨慎使用。',
|
||||
'Scope variables': '局域变量',
|
||||
'Single number will be treated as times, single string will be treated as chars, other non-array value will be turned into a single item array.':
|
||||
'单一数字值将被视为次数,单一字符串值将被视为字符数组,其他非数组值将被转换为值数组。',
|
||||
'A single number will be treated as a loop count, a single string will be treated as an array of characters, and other non-array values will be converted to arrays. The loop node ends when the loop count is reached, or when the array loop is completed. You can also add condition nodes to the loop to terminate it.':
|
||||
'单一数字值将被视为循环次数,单一字符串值将被视为字符数组,其他非数组值将被转换为数组。达到循环次数,或者将数组循环完成后,循环节点结束。你也可以在循环中添加条件节点,以终止循环。',
|
||||
Delay: '延时',
|
||||
'Delay a period of time and then continue or exit the process. Can be used to set wait or timeout times in parallel branches.':
|
||||
'延时一段时间,然后继续或退出流程。可以用于并行分支中等待其他分支或设置超时时间。',
|
||||
Duration: '时长',
|
||||
'End Status': '到时状态',
|
||||
'Select status': '选择状态',
|
||||
@ -151,17 +163,31 @@ export default {
|
||||
'Data record': '数据记录',
|
||||
|
||||
'Create record': '新增数据',
|
||||
'Add new record to a collection. You can use variables from upstream nodes to assign values to fields.':
|
||||
'向一个数据表中添加新的数据。可以使用上游节点里的变量为字段赋值。',
|
||||
'Update record': '更新数据',
|
||||
'Update records of a collection. You can use variables from upstream nodes as query conditions and field values.':
|
||||
'更新一个数据表中的数据。可以使用上游节点里的变量作为查询条件和数据值。',
|
||||
'Query record': '查询数据',
|
||||
'Multiple records': '多条数据',
|
||||
'Fail on no data': '无数据时报错',
|
||||
'Query records from a collection. You can use variables from upstream nodes as query conditions.':
|
||||
'查询一个数据表中的数据。可以使用上游节点里的变量作为查询条件。',
|
||||
'Allow multiple records as result': '允许结果是多条数据',
|
||||
'If checked, when there are multiple records in the query result, an array will be returned as the result, which can be operated on one by one using a loop node. Otherwise, only one record will be returned.':
|
||||
'选中后,当查询结果有多条记录时,会返回数组作为结果,可以使用循环节点对它逐条操作;否则,仅返回一条数据。',
|
||||
'Exit when query result is null': '查询结果为空时,退出流程',
|
||||
'Please select collection first': '请先选择数据表',
|
||||
'Only update records matching conditions': '只更新满足条件的数据',
|
||||
'Please add at least one condition': '请添加至少一个条件',
|
||||
'Fields that are not assigned a value will be set to the default value, and those that do not have a default value are set to null.':
|
||||
'Unassigned fields will be set to default values, and those without default values will be set to null.':
|
||||
'未被赋值的字段将被设置为默认值,没有默认值的设置为空值。',
|
||||
|
||||
'Delete record': '删除数据',
|
||||
'Delete records of a collection. Could use variables in workflow context as filter. All records match the filter will be deleted.':
|
||||
'删除一个数据表中的数据。可以使用上游节点里的变量作为过滤条件。所有满足条件的数据都将被删除。',
|
||||
|
||||
Aggregate: '聚合查询',
|
||||
'Counting, summing, finding maximum, minimum, and average values for multiple records of a collection or associated data of a record.':
|
||||
'对一个数据表里的多条数据或者一条数据里的关系数据进行统计、求和、求最大值、最小值、平均值。',
|
||||
'Aggregator function': '聚合函数',
|
||||
'Target type': '目标类型',
|
||||
'Data of collection': '数据表数据',
|
||||
@ -177,6 +203,8 @@ export default {
|
||||
'该节点的执行结果已被其他节点({{nodes}})引用,删除前请先移除引用。',
|
||||
|
||||
'HTTP request': 'HTTP 请求',
|
||||
'Send HTTP request to a URL. You can use the variables in the upstream nodes as request headers, parameters and request body.':
|
||||
'向指定 URL 发送 HTTP 请求。可以使用上游节点里的变量作为请求头、参数和请求体。',
|
||||
'HTTP method': 'HTTP 方法',
|
||||
URL: '地址',
|
||||
Headers: '请求头',
|
||||
|
@ -90,6 +90,7 @@ export default {
|
||||
title: `{{t("Aggregate", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'aggregate',
|
||||
group: 'collection',
|
||||
description: `{{t("Counting, summing, finding maximum, minimum, and average values for multiple records of a collection or associated data of a record.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
aggregator: {
|
||||
type: 'string',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { FormItem, FormLayout } from '@formily/antd';
|
||||
import { SchemaInitializer, SchemaInitializerItemOptions, Variable, useCollectionManager } from '@nocobase/client';
|
||||
import { FormLayout, FormItem } from '@formily/antd';
|
||||
import { SchemaInitializerItemOptions, Variable, useCollectionManager } from '@nocobase/client';
|
||||
import { Evaluator, evaluators, getOptions } from '@nocobase/evaluators/client';
|
||||
import { parse } from '@nocobase/utils/client';
|
||||
import { Radio } from 'antd';
|
||||
@ -29,7 +29,7 @@ const DynamicConfig = ({ value, onChange }) => {
|
||||
|
||||
return (
|
||||
<FormLayout layout="vertical">
|
||||
<FormItem label={t('Expression type', { ns: NAMESPACE })}>
|
||||
<FormItem colon label={t('Expression type', { ns: NAMESPACE })}>
|
||||
<Radio.Group
|
||||
value={value === false ? false : value || null}
|
||||
onChange={(ev) => {
|
||||
@ -41,7 +41,13 @@ const DynamicConfig = ({ value, onChange }) => {
|
||||
</Radio.Group>
|
||||
</FormItem>
|
||||
{value !== false ? (
|
||||
<FormItem label={t('Select dynamic expression', { ns: NAMESPACE })}>
|
||||
<FormItem
|
||||
label={t('Select dynamic expression', { ns: NAMESPACE })}
|
||||
extra={t(
|
||||
'Select the dynamic expression queried from the upstream node. You need to query it from an expression collection.',
|
||||
{ ns: NAMESPACE },
|
||||
)}
|
||||
>
|
||||
<Variable.Input value={value || null} onChange={(v) => onChange(v)} scope={scope} />
|
||||
</FormItem>
|
||||
) : null}
|
||||
@ -57,10 +63,12 @@ export default {
|
||||
title: `{{t("Calculation", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'calculation',
|
||||
group: 'control',
|
||||
description: `{{t("Calculate an expression based on a calculation engine and obtain a value as the result. Variables in the upstream nodes can be used in the expression. The expression can be static or dynamic one from an expression collections.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
dynamic: {
|
||||
type: 'string',
|
||||
'x-component': 'DynamicConfig',
|
||||
// description: `{{t("Select the dynamic expression queried from the upstream node. You need to query it from an expression collection.", { ns: "${NAMESPACE}" })}}`,
|
||||
default: false,
|
||||
},
|
||||
engine: {
|
||||
|
@ -161,6 +161,7 @@ function Calculation({ calculator, operands = [], onChange }) {
|
||||
value={calculator}
|
||||
onChange={(v) => onChange({ operands, calculator: v })}
|
||||
placeholder={lang('Calculator')}
|
||||
dropdownMatchSelectWidth={false}
|
||||
>
|
||||
{calculatorGroups
|
||||
.filter((group) => Boolean(getGroupCalculators(group.value).length))
|
||||
@ -316,6 +317,7 @@ export default {
|
||||
title: `{{t("Condition", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'condition',
|
||||
group: 'control',
|
||||
description: `{{t('Based on boolean result of the calculation to determine whether to "continue" or "exit" the process, or continue on different branches of "yes" and "no".', { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
rejectOnFalse: {
|
||||
type: 'boolean',
|
||||
|
@ -12,6 +12,7 @@ export default {
|
||||
title: `{{t("Create record", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'create',
|
||||
group: 'collection',
|
||||
description: `{{t("Add new record to a collection. You can use variables from upstream nodes to assign values to fields.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
collection,
|
||||
// multiple: {
|
||||
|
@ -6,6 +6,7 @@ export default {
|
||||
title: `{{t("Delay", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'delay',
|
||||
group: 'control',
|
||||
description: `{{t("Delay a period of time and then continue or exit the process. Can be used to set wait or timeout times in parallel branches.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
duration: {
|
||||
type: 'number',
|
||||
|
@ -9,6 +9,7 @@ export default {
|
||||
title: '{{t("Delete record")}}',
|
||||
type: 'destroy',
|
||||
group: 'collection',
|
||||
description: `{{t("Delete records of a collection. Could use variables in workflow context as filter. All records match the filter will be deleted.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
collection,
|
||||
params: {
|
||||
|
@ -39,11 +39,13 @@ import { JobStatusOptionsMap } from '../constants';
|
||||
import { NAMESPACE, lang } from '../locale';
|
||||
import request from './request';
|
||||
import { VariableOptions } from '../variable';
|
||||
import { NodeDescription } from '../components/NodeDescription';
|
||||
|
||||
export interface Instruction {
|
||||
title: string;
|
||||
type: string;
|
||||
group: string;
|
||||
description?: string;
|
||||
options?: { label: string; value: any; key: string }[];
|
||||
fieldset: { [key: string]: ISchema };
|
||||
view?: ISchema;
|
||||
@ -388,7 +390,7 @@ export function NodeDefaultView(props) {
|
||||
},
|
||||
[`${instruction.type}_${data.id}`]: {
|
||||
type: 'void',
|
||||
title: instruction.title,
|
||||
title: data.title,
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
@ -418,6 +420,16 @@ export function NodeDefaultView(props) {
|
||||
},
|
||||
},
|
||||
}
|
||||
: instruction.description
|
||||
? {
|
||||
description: {
|
||||
type: 'void',
|
||||
'x-component': NodeDescription,
|
||||
'x-component-props': {
|
||||
instruction,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
fieldset: {
|
||||
type: 'void',
|
||||
|
@ -31,25 +31,12 @@ export default {
|
||||
title: `{{t("Loop", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'loop',
|
||||
group: 'control',
|
||||
description: `{{t("By using a loop node, you can perform the same operation on multiple sets of data. The source of these sets can be either multiple records from a query node or multiple associated records of a single record. Loop node can also be used for iterating a certain number of times or for looping through each character in a string. However, excessive looping may cause performance issues, so use with caution.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
warning: {
|
||||
type: 'void',
|
||||
'x-component': Alert,
|
||||
'x-component-props': {
|
||||
type: 'warning',
|
||||
showIcon: true,
|
||||
message: `{{t("Loop will cause performance issue based on the quantity, please use with caution.", { ns: "${NAMESPACE}" })}}`,
|
||||
className: css`
|
||||
width: 100%;
|
||||
font-size: 85%;
|
||||
margin-bottom: 2em;
|
||||
`,
|
||||
},
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
title: `{{t("Loop target", { ns: "${NAMESPACE}" })}}`,
|
||||
description: `{{t("Single number will be treated as times, single string will be treated as chars, other non-array value will be turned into a single item array.", { ns: "${NAMESPACE}" })}}`,
|
||||
description: `{{t("A single number will be treated as a loop count, a single string will be treated as an array of characters, and other non-array values will be converted to arrays. The loop node ends when the loop count is reached, or when the array loop is completed. You can also add condition nodes to the loop to terminate it.", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Variable.Input',
|
||||
'x-component-props': {
|
||||
|
@ -33,6 +33,7 @@ export default {
|
||||
title: `{{t("Manual", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'manual',
|
||||
group: 'manual',
|
||||
description: `{{t("Could be used for manually submitting data, and determine whether to continue or exit. Workflow will generate a todo item for assigned user when it reaches a manual node, and continue processing after user submits the form.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
assignees: {
|
||||
type: 'array',
|
||||
|
@ -14,6 +14,7 @@ export default {
|
||||
title: `{{t("Parallel branch", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'parallel',
|
||||
group: 'control',
|
||||
description: `{{t("Run multiple branch processes in parallel.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
mode: {
|
||||
type: 'string',
|
||||
@ -35,7 +36,7 @@ export default {
|
||||
{
|
||||
value: 'race',
|
||||
label: `{{t('Any succeeded or failed', { ns: "${NAMESPACE}" })}}`,
|
||||
tooltip: `{{t('Continue after any branch succeeded, or exit after any branch failed', { ns: "${NAMESPACE}" })}}`,
|
||||
tooltip: `{{t('Continue after any branch succeeded, or exit after any branch failed.', { ns: "${NAMESPACE}" })}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -12,13 +12,15 @@ export default {
|
||||
title: `{{t("Query record", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'query',
|
||||
group: 'collection',
|
||||
description: `{{t("Query records from a collection. You can use variables from upstream nodes as query conditions.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
collection,
|
||||
multiple: {
|
||||
type: 'boolean',
|
||||
title: `{{t("Multiple records", { ns: "${NAMESPACE}" })}}`,
|
||||
title: `{{t("Allow multiple records as result", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
description: `{{t("If checked, when there are multiple records in the query result, an array will be returned as the result, which can be operated on one by one using a loop node. Otherwise, only one record will be returned.", { ns: "${NAMESPACE}" })}}`,
|
||||
},
|
||||
params: {
|
||||
type: 'object',
|
||||
@ -29,7 +31,7 @@ export default {
|
||||
},
|
||||
failOnEmpty: {
|
||||
type: 'boolean',
|
||||
title: `{{t("Fail on no data", { ns: "${NAMESPACE}" })}}`,
|
||||
title: `{{t("Exit when query result is null", { ns: "${NAMESPACE}" })}}`,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
},
|
||||
|
@ -8,6 +8,7 @@ export default {
|
||||
title: `{{t("HTTP request", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'request',
|
||||
group: 'extended',
|
||||
description: `{{t("Send HTTP request to a URL. You can use the variables in the upstream nodes as request headers, parameters and request body.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
method: {
|
||||
type: 'string',
|
||||
|
@ -11,6 +11,7 @@ export default {
|
||||
title: `{{t("Update record", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'update',
|
||||
group: 'collection',
|
||||
description: `{{t("Update records of a collection. You can use variables from upstream nodes as query conditions and field values.", { ns: "${NAMESPACE}" })}}`,
|
||||
fieldset: {
|
||||
collection,
|
||||
params: {
|
||||
|
@ -26,7 +26,7 @@ export const values = {
|
||||
`,
|
||||
},
|
||||
'x-component': 'CollectionFieldset',
|
||||
description: `{{t("Fields that are not assigned a value will be set to the default value, and those that do not have a default value are set to null.", { ns: "${NAMESPACE}" })}}`,
|
||||
description: `{{t("Unassigned fields will be set to default values, and those without default values will be set to null.", { ns: "${NAMESPACE}" })}}`,
|
||||
};
|
||||
|
||||
export const filter = {
|
||||
|
Loading…
Reference in New Issue
Block a user