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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
{ {
"Parallel branch": "分支", "Parallel branch": "并行分支",
"Run multiple branch processes in parallel.": "并行运行多个分支流程。", "Run multiple branch processes in parallel.": "并行运行多个分支流程。",
"Add branch": "增加分支", "Add branch": "增加分支",
"Mode": "执行模式", "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 { css, cx } from '@nocobase/client';
import { AddButton } from './AddButton'; import { AddButton } from './AddNodeContext';
import { useGetAriaLabelOfAddButton } from './hooks/useGetAriaLabelOfAddButton'; import { useGetAriaLabelOfAddButton } from './hooks/useGetAriaLabelOfAddButton';
import { Node } from './nodes'; import { Node } from './nodes';
import useStyles from './style'; import useStyles from './style';

View File

@ -18,6 +18,7 @@ import { useFlowContext } from './FlowContext';
import { lang } from './locale'; import { lang } from './locale';
import useStyles from './style'; import useStyles from './style';
import { TriggerConfig } from './triggers'; import { TriggerConfig } from './triggers';
import { AddNodeContextProvider } from './AddNodeContext';
export function CanvasContent({ entry }) { export function CanvasContent({ entry }) {
const { styles } = useStyles(); const { styles } = useStyles();
@ -27,41 +28,43 @@ export function CanvasContent({ entry }) {
return ( return (
<div className="workflow-canvas-wrapper"> <div className="workflow-canvas-wrapper">
<ErrorBoundary FallbackComponent={ErrorFallback} onError={console.error}> <ErrorBoundary FallbackComponent={ErrorFallback} onError={console.error}>
<div className="workflow-canvas" style={{ zoom: zoom / 100 }}> <AddNodeContextProvider>
<div <div className="workflow-canvas" style={{ zoom: zoom / 100 }}>
className={cx( <div
styles.branchBlockClass, className={cx(
css` styles.branchBlockClass,
margin-top: 0 !important; css`
`, margin-top: 0 !important;
)} `,
> )}
<div className={styles.branchClass}> >
{workflow?.executed ? ( <div className={styles.branchClass}>
<Alert {workflow?.executed ? (
type="warning" <Alert
message={lang('Executed workflow cannot be modified. Could be copied to a new version to modify.')} type="warning"
showIcon message={lang('Executed workflow cannot be modified. Could be copied to a new version to modify.')}
className={css` showIcon
margin-bottom: 1em; className={css`
`} margin-bottom: 1em;
/> `}
) : null} />
<TriggerConfig /> ) : null}
<div <TriggerConfig />
className={cx( <div
styles.branchBlockClass, className={cx(
css` styles.branchBlockClass,
margin-top: 0 !important; css`
`, margin-top: 0 !important;
)} `,
> )}
<Branch entry={entry} /> >
<Branch entry={entry} />
</div>
<div className={styles.terminalClass}>{lang('End')}</div>
</div> </div>
<div className={styles.terminalClass}>{lang('End')}</div>
</div> </div>
</div> </div>
</div> </AddNodeContextProvider>
</ErrorBoundary> </ErrorBoundary>
<div className="workflow-canvas-zoomer"> <div className="workflow-canvas-zoomer">
<Slider vertical reverse defaultValue={100} step={10} min={10} value={zoom} onChange={setZoom} /> <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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('branch').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(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click(); await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, 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'); await page.waitForLoadState('load');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click(); await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover(); await page.getByRole('button', { name: 'condition', exact: true }).click();
await page.getByLabel('rejectOnFalse').click(); await page.getByLabel('action-Action-Submit-workflows').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName);

View File

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

View File

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

View File

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

View File

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

View File

@ -160,6 +160,8 @@
"Continue when \"Yes\"": "“是”则继续", "Continue when \"Yes\"": "“是”则继续",
"Branch into \"Yes\" and \"No\"": "“是”和“否”分别继续", "Branch into \"Yes\" and \"No\"": "“是”和“否”分别继续",
"Condition expression": "条件表达式", "Condition expression": "条件表达式",
"Inside of \"Yes\" branch": "“是”分支内",
"Inside of \"No\" branch": "“否”分支内",
"Create record": "新增数据", "Create record": "新增数据",
"Add new record to a collection. You can use variables from upstream nodes to assign values to fields.": "Add new record to a collection. You can use variables from upstream nodes to assign values to fields.":
"向一个数据表中添加新的数据。可以使用上游节点里的变量为字段赋值。", "向一个数据表中添加新的数据。可以使用上游节点里的变量为字段赋值。",
@ -206,5 +208,10 @@
"Succeeded": "成功", "Succeeded": "成功",
"Test run": "测试执行", "Test run": "测试执行",
"Test run will do the actual data manipulating or API calling, please use with caution.": "测试执行会进行实际的数据操作或 API 调用,请谨慎使用。", "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 }) { export default function ({ app }) {
app.actions({ app.resourceManager.registerActionHandlers({
...make('workflows', workflows), ...make('workflows', workflows),
...make('workflows.nodes', { ...make('workflows.nodes', {
create: nodes.create, create: nodes.create,