feat(plugin-workflow): branch presetting (#5570)

* fix(client): fix core component bug and warnings

* feat(plugin-workflow): add preset and branching config before add node

* refactor(plugin-workflow): fix AddNodeContext and adjust styles

* fix(plugin-workflow): fix default config value in preset form

* fix(plugin-workflow): fix e2e cases

* fix(plugin-workflow-parallel): fix e2e test cases

* fix(plugin-workflow): fix e2e test cases
This commit is contained in:
Junyi 2024-11-08 13:43:39 +08:00 committed by GitHub
parent c728146160
commit a223f4448e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 748 additions and 362 deletions

View File

@ -8,7 +8,7 @@
*/
import { css } from '@emotion/css';
import { observer, RecursionField, useField, useFieldSchema, useForm } from '@formily/react';
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
import { Modal, ModalProps } from 'antd';
import classNames from 'classnames';
import React, { useMemo } from 'react';
@ -43,7 +43,6 @@ export const InternalActionModal: React.FC<ActionDrawerProps<ModalProps>> = obse
const { visible, setVisible, openSize = 'middle', modalProps } = useActionContext();
const actualWidth = width ?? openSizeWidthMap.get(openSize);
const schema = useFieldSchema();
const form = useForm();
const field = useField();
const { token } = useToken();
const tabContext = useTabsContext();
@ -91,7 +90,6 @@ export const InternalActionModal: React.FC<ActionDrawerProps<ModalProps>> = obse
open={visible}
onCancel={() => {
setVisible(false, true);
form.reset();
}}
className={classNames(
others.className,

View File

@ -45,7 +45,7 @@ const useIsSubPageClosedByPageMenu = () => {
export const ActionContextProvider: React.FC<ActionContextProps & { value?: ActionContextProps }> = (props) => {
const [submitted, setSubmitted] = useState(false); //是否有提交记录
const { visible } = { ...props, ...props.value } || {};
const { visible } = { ...props, ...props.value };
const { setSubmitted: setParentSubmitted } = { ...props, ...props.value };
const service = useBlockServiceInActionButton();
const isSubPageClosedByPageMenu = useIsSubPageClosedByPageMenu();

View File

@ -244,11 +244,12 @@ const SortableRow = (props: {
const { setNodeRef, isOver, active, over } = useSortable({
id,
});
const { rowIndex, ...others } = props;
const { ref, inView } = useInView({
threshold: 0,
triggerOnce: true,
initialInView: !!process.env.__E2E__ || isInSubTable || (props.rowIndex || 0) < INITIAL_ROWS_NUMBER,
initialInView: !!process.env.__E2E__ || isInSubTable || (rowIndex || 0) < INITIAL_ROWS_NUMBER,
skip: !!process.env.__E2E__ || isInSubTable,
});
@ -282,7 +283,7 @@ const SortableRow = (props: {
}
ref(node);
}}
{...props}
{...others}
className={classNames(props.className, { [className]: active && isOver })}
/>
</InViewContext.Provider>

View File

@ -355,6 +355,7 @@ export default class extends Instruction {
default: 0,
},
};
branching = true;
scope = {
renderEngineReference,
};

View File

@ -58,6 +58,7 @@ export default class extends Instruction {
default: 'all',
},
};
branching = true;
components = {
RadioWithTooltip,
};
@ -118,6 +119,7 @@ export default class extends Instruction {
icon={<PlusOutlined />}
onClick={() => setBranchCount(branchCount - 1)}
disabled={workflow.executed}
size="small"
/>
</div>
) : null
@ -145,6 +147,7 @@ export default class extends Instruction {
transform: rotate(-45deg);
}
`}
size="small"
onClick={() => setBranchCount(branchCount + 1)}
disabled={workflow.executed}
/>

View File

@ -75,8 +75,9 @@ test.describe('All succeeded', () => {
await parallelBranchNode.addBranchButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -87,8 +88,9 @@ test.describe('All succeeded', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -99,8 +101,9 @@ test.describe('All succeeded', () => {
await twoConditionNode.submitButton.click();
// 分支3添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
@ -210,8 +213,9 @@ test.describe('All succeeded', () => {
await parallelBranchNode.addBranchButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -222,8 +226,9 @@ test.describe('All succeeded', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -234,8 +239,9 @@ test.describe('All succeeded', () => {
await twoConditionNode.submitButton.click();
// 分支3添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
@ -344,8 +350,9 @@ test.describe('All succeeded', () => {
await parallelBranchNode.addBranchButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -356,8 +363,9 @@ test.describe('All succeeded', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -368,8 +376,9 @@ test.describe('All succeeded', () => {
await twoConditionNode.submitButton.click();
// 分支3添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
@ -477,8 +486,9 @@ test.describe('All succeeded', () => {
await parallelBranchNode.addBranchButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -489,8 +499,9 @@ test.describe('All succeeded', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -501,8 +512,9 @@ test.describe('All succeeded', () => {
await twoConditionNode.submitButton.click();
// 分支3添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);

View File

@ -78,8 +78,9 @@ test.describe('Any succeeded', () => {
await parallelBranchNode.addBranchButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -90,8 +91,9 @@ test.describe('Any succeeded', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -102,8 +104,9 @@ test.describe('Any succeeded', () => {
await twoConditionNode.submitButton.click();
// 分支3添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
@ -214,8 +217,9 @@ test.describe('Any succeeded', () => {
await parallelBranchNode.addBranchButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -226,8 +230,9 @@ test.describe('Any succeeded', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -238,8 +243,9 @@ test.describe('Any succeeded', () => {
await twoConditionNode.submitButton.click();
// 分支3添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
@ -351,8 +357,9 @@ test.describe('Any succeeded', () => {
await parallelBranchNode.addBranchButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -363,8 +370,9 @@ test.describe('Any succeeded', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -375,8 +383,9 @@ test.describe('Any succeeded', () => {
await twoConditionNode.submitButton.click();
// 分支3添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);

View File

@ -77,8 +77,9 @@ test.describe('Any succeeded or failed', () => {
await parallelBranchNode.submitButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -89,8 +90,9 @@ test.describe('Any succeeded or failed', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
@ -198,8 +200,9 @@ test.describe('Any succeeded or failed', () => {
await parallelBranchNode.submitButton.click();
// 分支1添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
@ -210,8 +213,9 @@ test.describe('Any succeeded or failed', () => {
await oneConditionNode.submitButton.click();
// 分支2添加判断节点
await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Continue when "Yes"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);

View File

@ -1,5 +1,5 @@
{
"Parallel branch": "分支",
"Parallel branch": "并行分支",
"Run multiple branch processes in parallel.": "并行运行多个分支流程。",
"Add branch": "增加分支",
"Mode": "执行模式",

View File

@ -1,143 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useCallback, useMemo, useState } from 'react';
import { Button, Dropdown, MenuProps } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { css, useAPIClient, useCompile, usePlugin } from '@nocobase/client';
import WorkflowPlugin from '.';
import { useFlowContext } from './FlowContext';
import { NAMESPACE } from './locale';
import { Instruction } from './nodes';
import useStyles from './style';
interface AddButtonProps {
upstream;
branchIndex?: number | null;
[key: string]: any;
}
export function AddButton(props: AddButtonProps) {
const { upstream, branchIndex = null } = props;
const engine = usePlugin(WorkflowPlugin);
const compile = useCompile();
const api = useAPIClient();
const { workflow, refresh } = useFlowContext() ?? {};
const instructionList = Array.from(engine.instructions.getValues()) as Instruction[];
const { styles } = useStyles();
const [creating, setCreating] = useState(false);
const groups = useMemo(() => {
return [
{ key: 'control', label: `{{t("Control", { ns: "${NAMESPACE}" })}}` },
{ key: 'calculation', label: `{{t("Calculation", { ns: "${NAMESPACE}" })}}` },
{ key: 'collection', label: `{{t("Collection operations", { ns: "${NAMESPACE}" })}}` },
{ key: 'manual', label: `{{t("Manual", { ns: "${NAMESPACE}" })}}` },
{ key: 'extended', label: `{{t("Extended types", { ns: "${NAMESPACE}" })}}` },
]
.map((group) => {
const groupInstructions = instructionList.filter(
(item) =>
item.group === group.key &&
(item.isAvailable ? item.isAvailable({ engine, workflow, upstream, branchIndex }) : true),
);
return {
...group,
type: 'group',
children: groupInstructions.map((item) => ({
role: 'button',
'aria-label': item.type,
key: item.type,
label: item.title,
type: item.options ? 'subMenu' : null,
children: item.options
? item.options.map((option) => ({
role: 'button',
'aria-label': option.key,
key: option.key,
label: option.label,
}))
: null,
})),
};
})
.filter((group) => group.children.length);
}, [branchIndex, engine, instructionList, upstream, workflow]);
const onCreate = useCallback(
async ({ keyPath }) => {
const type = keyPath.pop();
const [optionKey] = keyPath;
const instruction = engine.instructions.get(type);
const config = instruction.createDefaultConfig();
if (optionKey) {
const { value } = instruction.options?.find((item) => item.key === optionKey) ?? {};
Object.assign(config, typeof value === 'function' ? value() : value);
}
if (workflow) {
setCreating(true);
try {
await api.resource('workflows.nodes', workflow.id).create({
values: {
type,
upstreamId: upstream?.id ?? null,
branchIndex,
title: compile(instruction.title),
config,
},
});
refresh();
} catch (err) {
console.error(err);
} finally {
setCreating(false);
}
}
},
[api, branchIndex, engine.instructions, refresh, upstream?.id, workflow],
);
const menu = useMemo<MenuProps>(() => {
return {
onClick: onCreate,
items: compile(groups),
};
}, [groups, onCreate]);
if (!workflow) {
return null;
}
return (
<div className={styles.addButtonClass}>
<Dropdown
trigger={['click']}
menu={menu}
disabled={workflow.executed}
overlayClassName={css`
.ant-dropdown-menu-root {
max-height: 30em;
overflow-y: auto;
}
`}
>
<Button
aria-label={props['aria-label'] || 'add-button'}
shape="circle"
icon={<PlusOutlined />}
loading={creating}
/>
</Dropdown>
</div>
);
}

View File

@ -0,0 +1,412 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
import { createForm } from '@formily/core';
import { observer, useForm } from '@formily/react';
import {
ActionContextProvider,
css,
SchemaComponent,
useActionContext,
useAPIClient,
useCancelAction,
useCompile,
usePlugin,
} from '@nocobase/client';
import WorkflowPlugin, { Instruction, useStyles } from '.';
import { useFlowContext } from './FlowContext';
import { lang, NAMESPACE } from './locale';
import { RadioWithTooltip } from './components';
import { uid } from '@nocobase/utils/client';
import { Button, Dropdown } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
interface AddButtonProps {
upstream;
branchIndex?: number | null;
[key: string]: any;
}
export function AddButton(props: AddButtonProps) {
const { upstream, branchIndex = null } = props;
const engine = usePlugin(WorkflowPlugin);
const compile = useCompile();
const { workflow } = useFlowContext() ?? {};
const instructionList = Array.from(engine.instructions.getValues()) as Instruction[];
const { styles } = useStyles();
const { onCreate, creating } = useAddNodeContext();
const groups = useMemo(() => {
const result = [
{ key: 'control', label: `{{t("Control", { ns: "${NAMESPACE}" })}}` },
{ key: 'calculation', label: `{{t("Calculation", { ns: "${NAMESPACE}" })}}` },
{ key: 'collection', label: `{{t("Collection operations", { ns: "${NAMESPACE}" })}}` },
{ key: 'manual', label: `{{t("Manual", { ns: "${NAMESPACE}" })}}` },
{ key: 'extended', label: `{{t("Extended types", { ns: "${NAMESPACE}" })}}` },
]
.map((group) => {
const groupInstructions = instructionList.filter(
(item) =>
item.group === group.key &&
(item.isAvailable ? item.isAvailable({ engine, workflow, upstream, branchIndex }) : true),
);
return {
...group,
type: 'group',
children: groupInstructions.map((item) => ({
role: 'button',
'aria-label': item.type,
key: item.type,
label: item.title,
})),
};
})
.filter((group) => group.children.length);
return compile(result);
}, [branchIndex, compile, engine, instructionList, upstream, workflow]);
const onClick = useCallback(
async ({ keyPath }) => {
const [type] = keyPath;
onCreate({ type, upstream, branchIndex });
},
[branchIndex, onCreate, upstream],
);
if (!workflow) {
return null;
}
return (
<div className={styles.addButtonClass}>
<Dropdown
menu={{
items: groups,
onClick,
}}
disabled={workflow.executed}
overlayClassName={css`
.ant-dropdown-menu-root {
max-height: 30em;
overflow-y: auto;
}
`}
>
<Button
aria-label={props['aria-label'] || 'add-button'}
shape="circle"
icon={<PlusOutlined />}
loading={creating?.upstreamId == upstream?.id && creating?.branchIndex === branchIndex}
size="small"
/>
</Dropdown>
</div>
);
}
function useAddNodeSubmitAction() {
const form = useForm();
const api = useAPIClient();
const { workflow, refresh } = useFlowContext();
const { presetting, setPresetting, setCreating } = useAddNodeContext();
const ctx = useActionContext();
return {
async run() {
if (!presetting) {
return;
}
await form.submit();
setCreating(presetting.data);
try {
const {
data: { data: newNode },
} = await api.resource('workflows.nodes', workflow.id).create({
values: {
...presetting.data,
config: {
...presetting.data.config,
...form.values.config,
},
},
});
if (form.values.downstreamBranchIndex !== false && newNode.downstreamId) {
await api.resource('flow_nodes').update({
filterByTk: newNode.downstreamId,
values: {
branchIndex: form.values.downstreamBranchIndex,
upstream: {
id: newNode.id,
downstreamId: null,
},
},
updateAssociationValues: ['upstream'],
});
}
ctx.setVisible(false);
setPresetting(null);
refresh();
} catch (err) {
console.error(err);
} finally {
setCreating(null);
}
},
};
}
const AddNodeContext = createContext(null);
export function useAddNodeContext() {
return useContext(AddNodeContext);
}
const defaultBranchingOptions = [
{
label: `{{t('After end of branches', { ns: "${NAMESPACE}" })}}`,
value: false,
},
{
label: `{{t('Inside of branch', { ns: "${NAMESPACE}" })}}`,
value: 0,
},
];
const DownstreamBranchIndex = observer((props) => {
const { presetting } = useAddNodeContext();
const { nodes } = useFlowContext();
const { values } = useForm();
const options = useMemo(() => {
if (!presetting?.instruction) {
return [];
}
const { instruction, data } = presetting;
const downstream = data.upstreamId
? nodes.find((item) => item.upstreamId === data.upstreamId && item.branchIndex === data.branchIndex)
: nodes.find((item) => item.upstreamId === null);
if (!downstream) {
return [];
}
const branching =
typeof instruction.branching === 'function' ? instruction.branching(values.config ?? {}) : instruction.branching;
if (!branching) {
return [];
}
return branching === true ? defaultBranchingOptions : branching;
}, [presetting, nodes, values.config]);
if (!options.length) {
return null;
}
const { data } = presetting;
return (
<SchemaComponent
components={{
RadioWithTooltip,
}}
schema={{
name: `${data.type ?? 'unknown'}-${data.upstreamId ?? 'root'}-${data.branchIndex}`,
type: 'void',
properties: {
downstreamBranchIndex: {
type: 'number',
title: lang('Move all downstream nodes to', { ns: NAMESPACE }),
'x-decorator': 'FormItem',
'x-component': 'RadioWithTooltip',
'x-component-props': {
options,
direction: 'vertical',
},
default: false,
required: true,
},
},
}}
/>
);
// return (
// <FormItem label={lang('Move all downstream nodes to', { ns: NAMESPACE })}>
// <RadioWithTooltip {...props} options={options} defaultValue={-1} direction="vertical" />
// </FormItem>
// );
});
function PresetFieldset() {
const { presetting } = useAddNodeContext();
if (!presetting?.instruction.presetFieldset) {
return null;
}
return (
<SchemaComponent
schema={{
type: 'void',
properties: {
config: {
type: 'object',
properties: presetting.instruction.presetFieldset,
},
},
}}
/>
);
}
export function AddNodeContextProvider(props) {
const api = useAPIClient();
const compile = useCompile();
const engine = usePlugin(WorkflowPlugin);
const [creating, setCreating] = useState(null);
const [presetting, setPresetting] = useState(null);
const [formValueChanged, setFormValueChanged] = useState(false);
const { workflow, nodes, refresh } = useFlowContext() ?? {};
const form = useMemo(() => createForm(), []);
const onModalCancel = useCallback(
(visible) => {
if (!visible) {
form.reset();
form.clearFormGraph('*');
setPresetting(null);
}
},
[form],
);
const create = useCallback(
async (data) => {
setCreating(data);
try {
await api.resource('workflows.nodes', workflow.id).create({
values: data,
});
refresh();
} catch (err) {
console.error(err);
} finally {
setCreating(null);
}
},
[api, refresh, workflow.id],
);
const onCreate = useCallback(
({ type, upstream, branchIndex }) => {
const instruction = engine.instructions.get(type);
if (!instruction) {
console.error(`Instruction "${type}" not found`);
return;
}
const data = {
key: uid(),
type,
upstreamId: upstream?.id ?? null,
branchIndex,
title: compile(instruction.title),
config: instruction.createDefaultConfig?.() ?? {},
};
const downstream = upstream?.id
? nodes.find((item) => item.upstreamId === data.upstreamId && item.branchIndex === data.branchIndex)
: nodes.find((item) => item.upstreamId === null);
if (
instruction.presetFieldset ||
((typeof instruction.branching === 'function' ? instruction.branching(data.config) : instruction.branching) &&
downstream)
) {
setPresetting({ data, instruction });
return;
}
create(data);
},
[compile, create, engine.instructions],
);
return (
<AddNodeContext.Provider value={{ presetting, setPresetting, onCreate, creating, setCreating }}>
{props.children}
<ActionContextProvider
value={{
visible: Boolean(presetting),
setVisible: onModalCancel,
formValueChanged,
setFormValueChanged,
openSize: 'small',
}}
>
<SchemaComponent
components={{
DownstreamBranchIndex,
PresetFieldset,
}}
scope={{
useCancelAction,
useAddNodeSubmitAction,
}}
schema={{
name: `modal`,
type: 'void',
'x-decorator': 'FormV2',
'x-decorator-props': {
form,
},
'x-component': 'Action.Modal',
title: `{{ t("Add node", { ns: "${NAMESPACE}" }) }}`,
properties: {
config: {
type: 'void',
'x-component': 'PresetFieldset',
},
downstreamBranchIndex: {
type: 'void',
'x-component': 'DownstreamBranchIndex',
},
footer: {
'x-component': 'Action.Modal.Footer',
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
properties: {
cancel: {
type: 'void',
title: '{{ t("Cancel") }}',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useCancelAction }}',
},
},
submit: {
type: 'void',
title: `{{ t("Submit") }}`,
'x-component': 'Action',
'x-component-props': {
type: 'primary',
htmlType: 'submit',
useAction: '{{ useAddNodeSubmitAction }}',
},
},
},
},
},
},
},
}}
/>
</ActionContextProvider>
</AddNodeContext.Provider>
);
}

View File

@ -12,7 +12,7 @@ import { CloseOutlined } from '@ant-design/icons';
import { css, cx } from '@nocobase/client';
import { AddButton } from './AddButton';
import { AddButton } from './AddNodeContext';
import { useGetAriaLabelOfAddButton } from './hooks/useGetAriaLabelOfAddButton';
import { Node } from './nodes';
import useStyles from './style';

View File

@ -18,6 +18,7 @@ import { useFlowContext } from './FlowContext';
import { lang } from './locale';
import useStyles from './style';
import { TriggerConfig } from './triggers';
import { AddNodeContextProvider } from './AddNodeContext';
export function CanvasContent({ entry }) {
const { styles } = useStyles();
@ -27,6 +28,7 @@ export function CanvasContent({ entry }) {
return (
<div className="workflow-canvas-wrapper">
<ErrorBoundary FallbackComponent={ErrorFallback} onError={console.error}>
<AddNodeContextProvider>
<div className="workflow-canvas" style={{ zoom: zoom / 100 }}>
<div
className={cx(
@ -62,6 +64,7 @@ export function CanvasContent({ entry }) {
</div>
</div>
</div>
</AddNodeContextProvider>
</ErrorBoundary>
<div className="workflow-canvas-zoomer">
<Slider vertical reverse defaultValue={100} step={10} min={10} value={zoom} onChange={setZoom} />

View File

@ -91,8 +91,9 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -239,8 +240,9 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -383,8 +385,9 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -529,8 +532,9 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);

View File

@ -65,8 +65,9 @@ test('Collection event add data trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -178,8 +179,9 @@ test('Collection event add data trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -291,8 +293,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -406,8 +409,9 @@ test('Collection event add data trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);

View File

@ -68,8 +68,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -195,8 +196,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -319,8 +321,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -446,8 +449,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -594,8 +598,9 @@ test('Collection event add data trigger, determine the trigger node integer vari
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -752,8 +757,9 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -900,8 +906,9 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -1051,8 +1058,9 @@ test('Collection event add data trigger, determine the trigger node integer vari
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);

View File

@ -65,8 +65,9 @@ test('Collection event add data trigger, determine trigger node integer field va
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -189,8 +190,9 @@ test('Collection event Add Data Trigger, determines that the trigger node intege
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -310,8 +312,9 @@ test('Collection event Add Data Trigger, determines that the trigger node intege
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
@ -431,8 +434,9 @@ test('Collection event add data trigger, determines that the trigger node intege
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByText('Branch into "Yes" and "No"').click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);

View File

@ -69,8 +69,8 @@ test('Collection event add data trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -152,8 +152,8 @@ test('Collection event add data trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -236,8 +236,8 @@ test('Collection event Add Data Trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -322,8 +322,8 @@ test('Collection event add data trigger, determines that the trigger node single
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -432,8 +432,8 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -546,8 +546,8 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -657,8 +657,8 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -773,8 +773,8 @@ test('Collection event add data trigger, determine trigger node integer variable
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);

View File

@ -67,8 +67,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -157,8 +157,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -248,8 +248,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -337,8 +337,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -452,8 +452,8 @@ test('Collection event add data trigger, Formula engine, determine the trigger n
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -570,8 +570,8 @@ test('Collection event add data trigger, Formula engine, determine trigger node
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -686,8 +686,8 @@ test('Collection event add data trigger, Formula engine, determine trigger node
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -804,8 +804,8 @@ test('Collection event add data trigger, Formula engine, determine the trigger n
await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);

View File

@ -64,8 +64,8 @@ test('Collection event add data trigger, Math engine, determine trigger node int
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -155,8 +155,8 @@ test('Collection event Add Data Trigger, Math engine, determines that the trigge
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -246,8 +246,8 @@ test('Collection event Add Data Trigger, Math engine, determines that the trigge
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
@ -336,8 +336,8 @@ test('Collection event add data trigger, Math engine, determines that the trigge
await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);

View File

@ -20,6 +20,12 @@ import useStyles from '../style';
import { useWorkflowVariableOptions, WorkflowVariableTextArea } from '../variable';
import { CalculationConfig } from '../components/Calculation';
const BRANCH_INDEX = {
DEFAULT: null,
ON_TRUE: 1,
ON_FALSE: 0,
} as const;
export default class extends Instruction {
title = `{{t("Condition", { ns: "${NAMESPACE}" })}}`;
type = 'condition';
@ -107,18 +113,44 @@ export default class extends Instruction {
required: true,
},
};
options = [
presetFieldset = {
rejectOnFalse: {
type: 'boolean',
title: `{{t("Mode", { ns: "${NAMESPACE}" })}}`,
'x-decorator': 'FormItem',
'x-component': 'Radio.Group',
enum: [
{
label: `{{t('Continue when "Yes"', { ns: "${NAMESPACE}" })}}`,
key: 'rejectOnFalse',
value: { rejectOnFalse: true },
value: true,
},
{
label: `{{t('Branch into "Yes" and "No"', { ns: "${NAMESPACE}" })}}`,
key: 'branch',
value: { rejectOnFalse: false },
value: false,
},
],
default: true,
},
};
branching = ({ rejectOnFalse = true } = {}) => {
return rejectOnFalse
? false
: [
{
label: `{{t('After end of branches', { ns: "${NAMESPACE}" })}}`,
value: false,
},
{
label: `{{t('Inside of "Yes" branch', { ns: "${NAMESPACE}" })}}`,
value: BRANCH_INDEX.ON_TRUE,
},
{
label: `{{t('Inside of "No" branch', { ns: "${NAMESPACE}" })}}`,
value: BRANCH_INDEX.ON_FALSE,
},
];
};
scope = {
renderEngineReference,

View File

@ -34,7 +34,7 @@ import {
import { parse, str2moment } from '@nocobase/utils/client';
import WorkflowPlugin from '..';
import { AddButton } from '../AddButton';
import { AddButton } from '../AddNodeContext';
import { useFlowContext } from '../FlowContext';
import { DrawerDescription } from '../components/DrawerDescription';
import { StatusButton } from '../components/StatusButton';
@ -51,27 +51,40 @@ export type NodeAvailableContext = {
branchIndex: number;
};
type Config = Record<string, any>;
type Options = { label: string; value: any }[];
export abstract class Instruction {
title: string;
type: string;
group: string;
description?: string;
/**
* @experimental
* @deprecated migrate to `presetFieldset` instead
*/
options?: { label: string; value: any; key: string }[];
fieldset: Record<string, ISchema>;
/**
* @experimental
*/
presetFieldset?: Record<string, ISchema>;
/**
* To presentation if the instruction is creating a branch
* @experimental
*/
branching?: boolean | Options | ((config: Config) => boolean | Options);
/**
* @experimental
*/
view?: ISchema;
scope?: { [key: string]: any };
components?: { [key: string]: any };
scope?: Record<string, any>;
components?: Record<string, any>;
Component?(props): JSX.Element;
/**
* @experimental
*/
createDefaultConfig?(): Record<string, any> {
createDefaultConfig?(): Config {
return {};
}
useVariables?(node, options?: UseVariableOptions): VariableOption;
@ -243,6 +256,7 @@ export function RemoveButton() {
icon={<DeleteOutlined />}
onClick={onRemove}
className="workflow-node-remove-button"
size="small"
/>
);
}
@ -568,20 +582,19 @@ export function NodeDefaultView(props) {
'Node with unknown type will cause error. Please delete it or check plugin which provide this type.',
)}
>
<div
role="button"
aria-label={`_untyped-${editingTitle}`}
className={cx(styles.nodeCardClass, 'invalid')}
onClick={onOpenDrawer}
>
<div role="button" aria-label={`_untyped-${editingTitle}`} className={cx(styles.nodeCardClass, 'invalid')}>
<div className={styles.nodeHeaderClass}>
<div className={cx(styles.nodeMetaClass, 'workflow-node-meta')}>
<Tag color="error">{lang('Unknown node')}</Tag>
<span className="workflow-node-id">{data.id}</span>
</div>
<Input.TextArea value={editingTitle} disabled autoSize />
<div className="workflow-node-actions">
<RemoveButton />
<JobButton />
</div>
</div>
<Input.TextArea value={editingTitle} disabled autoSize />
</div>
</Tooltip>
</div>
);
@ -597,10 +610,16 @@ export function NodeDefaultView(props) {
className={cx(styles.nodeCardClass, { configuring: editingConfig })}
onClick={onOpenDrawer}
>
<div className={styles.nodeHeaderClass}>
<div className={cx(styles.nodeMetaClass, 'workflow-node-meta')}>
<Tag>{typeTitle}</Tag>
<span className="workflow-node-id">{data.id}</span>
</div>
<div className="workflow-node-actions">
<RemoveButton />
<JobButton />
</div>
</div>
<Input.TextArea
disabled={workflow.executed}
value={editingTitle}
@ -608,8 +627,6 @@ export function NodeDefaultView(props) {
onBlur={(ev) => onChangeTitle(ev.target.value)}
autoSize
/>
<RemoveButton />
<JobButton />
<ActionContextProvider
value={{
visible: editingConfig,

View File

@ -263,8 +263,8 @@ const useStyles = createStyles(({ css, token }) => {
.workflow-node-remove-button {
display: none;
position: absolute;
right: 0.5em;
top: 0.5em;
right: 0;
top: 0;
color: ${token.colorText};
&[disabled] {
@ -312,19 +312,24 @@ const useStyles = createStyles(({ css, token }) => {
nodeJobButtonClass: css`
display: flex;
position: absolute;
top: calc(1em - 1px);
right: 1em;
top: 0;
right: 0;
justify-content: center;
align-items: center;
color: ${token.colorTextLightSolid};
`,
nodeHeaderClass: css`
display: flex;
margin-bottom: 0.5em;
.workflow-node-actions {
position: relative;
}
`,
nodeMetaClass: css`
margin-bottom: 0.5em;
flex-grow: 1;
.workflow-node-id {
color: ${token.colorTextDescription};
@ -352,7 +357,6 @@ const useStyles = createStyles(({ css, token }) => {
`,
nodeJobResultClass: css`
padding: 1em;
background-color: #f3f3f3;
`,

View File

@ -240,9 +240,11 @@ export const TriggerConfig = () => {
className={cx(styles.nodeCardClass, 'invalid')}
onClick={onOpenDrawer}
>
<div className={styles.nodeHeaderClass}>
<div className={cx(styles.nodeMetaClass, 'workflow-node-meta')}>
<Tag color="error">{lang('Unknown trigger')}</Tag>
</div>
</div>
<div className="workflow-node-title">
<Input.TextArea value={editingTitle} disabled autoSize />
</div>
@ -260,12 +262,17 @@ export const TriggerConfig = () => {
className={cx(styles.nodeCardClass)}
onClick={onOpenDrawer}
>
<div className={styles.nodeHeaderClass}>
<div className={cx(styles.nodeMetaClass, 'workflow-node-meta')}>
<Tag color="gold">
<ThunderboltOutlined />
<span className="type">{compile(trigger.title)}</span>
</Tag>
</div>
<div className="workflow-node-actions">
<TriggerExecution />
</div>
</div>
<div className="workflow-node-title">
<Input.TextArea
value={editingTitle}
@ -275,7 +282,6 @@ export const TriggerConfig = () => {
disabled={workflow.executed}
/>
</div>
<TriggerExecution />
<ActionContextProvider
value={{
visible: editingConfig,

View File

@ -160,6 +160,8 @@
"Continue when \"Yes\"": "“是”则继续",
"Branch into \"Yes\" and \"No\"": "“是”和“否”分别继续",
"Condition expression": "条件表达式",
"Inside of \"Yes\" branch": "“是”分支内",
"Inside of \"No\" branch": "“否”分支内",
"Create record": "新增数据",
"Add new record to a collection. You can use variables from upstream nodes to assign values to fields.":
"向一个数据表中添加新的数据。可以使用上游节点里的变量为字段赋值。",
@ -206,5 +208,10 @@
"Succeeded": "成功",
"Test run": "测试执行",
"Test run will do the actual data manipulating or API calling, please use with caution.": "测试执行会进行实际的数据操作或 API 调用,请谨慎使用。",
"No variable": "无变量"
"No variable": "无变量",
"Add node": "添加节点",
"Move all downstream nodes to": "将所有下游节点移至",
"After end of branches": "分支结束后",
"Inside of branch": "分支内"
}

View File

@ -22,7 +22,7 @@ function make(name, mod) {
}
export default function ({ app }) {
app.actions({
app.resourceManager.registerActionHandlers({
...make('workflows', workflows),
...make('workflows.nodes', {
create: nodes.create,