From a223f4448ee557c5ccfdd8aa31802038d0701513 Mon Sep 17 00:00:00 2001 From: Junyi Date: Fri, 8 Nov 2024 13:43:39 +0800 Subject: [PATCH] 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 --- .../antd/action/Action.Modal.tsx | 4 +- .../schema-component/antd/action/context.tsx | 2 +- .../schema-component/antd/table-v2/Table.tsx | 5 +- .../src/client/LoopInstruction.tsx | 1 + .../src/client/ParallelInstruction.tsx | 3 + .../client/__e2e__/parallelBranch1.test.ts | 60 ++- .../client/__e2e__/parallelBranch2.test.ts | 45 +- .../client/__e2e__/parallelBranch3.test.ts | 20 +- .../src/locale/zh-CN.json | 2 +- .../plugin-workflow/src/client/AddButton.tsx | 143 ------ .../src/client/AddNodeContext.tsx | 412 ++++++++++++++++++ .../plugin-workflow/src/client/Branch.tsx | 2 +- .../src/client/CanvasContent.tsx | 67 +-- .../BranchIntoYesAndNoBasicType.test.ts | 20 +- .../BranchIntoYesAndNoBasicType1.test.ts | 20 +- .../BranchIntoYesAndNoFormulaEngine.test.ts | 40 +- .../BranchIntoYesAndNoMathEngine.test.ts | 20 +- .../continueWhenYesBasicType.test.ts | 32 +- .../continueWhenYesFormulaEngine.test.ts | 32 +- .../continueWhenYesMathEngine.test.ts | 16 +- .../src/client/nodes/condition.tsx | 54 ++- .../src/client/nodes/index.tsx | 59 ++- .../plugin-workflow/src/client/style.tsx | 18 +- .../src/client/triggers/index.tsx | 22 +- .../plugin-workflow/src/locale/zh-CN.json | 9 +- .../src/server/actions/index.ts | 2 +- 26 files changed, 748 insertions(+), 362 deletions(-) delete mode 100644 packages/plugins/@nocobase/plugin-workflow/src/client/AddButton.tsx create mode 100644 packages/plugins/@nocobase/plugin-workflow/src/client/AddNodeContext.tsx diff --git a/packages/core/client/src/schema-component/antd/action/Action.Modal.tsx b/packages/core/client/src/schema-component/antd/action/Action.Modal.tsx index 5478cc031..c22ae8158 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.Modal.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.Modal.tsx @@ -8,7 +8,7 @@ */ import { css } from '@emotion/css'; -import { observer, RecursionField, useField, useFieldSchema, useForm } from '@formily/react'; +import { observer, RecursionField, useField, useFieldSchema } from '@formily/react'; import { Modal, ModalProps } from 'antd'; import classNames from 'classnames'; import React, { useMemo } from 'react'; @@ -43,7 +43,6 @@ export const InternalActionModal: React.FC> = obse const { visible, setVisible, openSize = 'middle', modalProps } = useActionContext(); const actualWidth = width ?? openSizeWidthMap.get(openSize); const schema = useFieldSchema(); - const form = useForm(); const field = useField(); const { token } = useToken(); const tabContext = useTabsContext(); @@ -91,7 +90,6 @@ export const InternalActionModal: React.FC> = obse open={visible} onCancel={() => { setVisible(false, true); - form.reset(); }} className={classNames( others.className, diff --git a/packages/core/client/src/schema-component/antd/action/context.tsx b/packages/core/client/src/schema-component/antd/action/context.tsx index 14617b3b4..8eb71bd25 100644 --- a/packages/core/client/src/schema-component/antd/action/context.tsx +++ b/packages/core/client/src/schema-component/antd/action/context.tsx @@ -45,7 +45,7 @@ const useIsSubPageClosedByPageMenu = () => { export const ActionContextProvider: React.FC = (props) => { const [submitted, setSubmitted] = useState(false); //是否有提交记录 - const { visible } = { ...props, ...props.value } || {}; + const { visible } = { ...props, ...props.value }; const { setSubmitted: setParentSubmitted } = { ...props, ...props.value }; const service = useBlockServiceInActionButton(); const isSubPageClosedByPageMenu = useIsSubPageClosedByPageMenu(); diff --git a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx index c96b8dc50..871399f5e 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx @@ -244,11 +244,12 @@ const SortableRow = (props: { const { setNodeRef, isOver, active, over } = useSortable({ id, }); + const { rowIndex, ...others } = props; const { ref, inView } = useInView({ threshold: 0, triggerOnce: true, - initialInView: !!process.env.__E2E__ || isInSubTable || (props.rowIndex || 0) < INITIAL_ROWS_NUMBER, + initialInView: !!process.env.__E2E__ || isInSubTable || (rowIndex || 0) < INITIAL_ROWS_NUMBER, skip: !!process.env.__E2E__ || isInSubTable, }); @@ -282,7 +283,7 @@ const SortableRow = (props: { } ref(node); }} - {...props} + {...others} className={classNames(props.className, { [className]: active && isOver })} /> diff --git a/packages/plugins/@nocobase/plugin-workflow-loop/src/client/LoopInstruction.tsx b/packages/plugins/@nocobase/plugin-workflow-loop/src/client/LoopInstruction.tsx index 6a26da0a3..b3e72c902 100644 --- a/packages/plugins/@nocobase/plugin-workflow-loop/src/client/LoopInstruction.tsx +++ b/packages/plugins/@nocobase/plugin-workflow-loop/src/client/LoopInstruction.tsx @@ -355,6 +355,7 @@ export default class extends Instruction { default: 0, }, }; + branching = true; scope = { renderEngineReference, }; diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/ParallelInstruction.tsx b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/ParallelInstruction.tsx index 1a7297620..13006e1bc 100644 --- a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/ParallelInstruction.tsx +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/ParallelInstruction.tsx @@ -58,6 +58,7 @@ export default class extends Instruction { default: 'all', }, }; + branching = true; components = { RadioWithTooltip, }; @@ -118,6 +119,7 @@ export default class extends Instruction { icon={} onClick={() => setBranchCount(branchCount - 1)} disabled={workflow.executed} + size="small" /> ) : null @@ -145,6 +147,7 @@ export default class extends Instruction { transform: rotate(-45deg); } `} + size="small" onClick={() => setBranchCount(branchCount + 1)} disabled={workflow.executed} /> diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch1.test.ts b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch1.test.ts index 9a994ee1e..318d789ce 100644 --- a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch1.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch1.test.ts @@ -75,8 +75,9 @@ test.describe('All succeeded', () => { await parallelBranchNode.addBranchButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -87,8 +88,9 @@ test.describe('All succeeded', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -99,8 +101,9 @@ test.describe('All succeeded', () => { await twoConditionNode.submitButton.click(); // 分支3添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); @@ -210,8 +213,9 @@ test.describe('All succeeded', () => { await parallelBranchNode.addBranchButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -222,8 +226,9 @@ test.describe('All succeeded', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -234,8 +239,9 @@ test.describe('All succeeded', () => { await twoConditionNode.submitButton.click(); // 分支3添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); @@ -344,8 +350,9 @@ test.describe('All succeeded', () => { await parallelBranchNode.addBranchButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -356,8 +363,9 @@ test.describe('All succeeded', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -368,8 +376,9 @@ test.describe('All succeeded', () => { await twoConditionNode.submitButton.click(); // 分支3添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); @@ -477,8 +486,9 @@ test.describe('All succeeded', () => { await parallelBranchNode.addBranchButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -489,8 +499,9 @@ test.describe('All succeeded', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -501,8 +512,9 @@ test.describe('All succeeded', () => { await twoConditionNode.submitButton.click(); // 分支3添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch2.test.ts b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch2.test.ts index d4158c896..a5906c431 100644 --- a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch2.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch2.test.ts @@ -78,8 +78,9 @@ test.describe('Any succeeded', () => { await parallelBranchNode.addBranchButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -90,8 +91,9 @@ test.describe('Any succeeded', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -102,8 +104,9 @@ test.describe('Any succeeded', () => { await twoConditionNode.submitButton.click(); // 分支3添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); @@ -214,8 +217,9 @@ test.describe('Any succeeded', () => { await parallelBranchNode.addBranchButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -226,8 +230,9 @@ test.describe('Any succeeded', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -238,8 +243,9 @@ test.describe('Any succeeded', () => { await twoConditionNode.submitButton.click(); // 分支3添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); @@ -351,8 +357,9 @@ test.describe('Any succeeded', () => { await parallelBranchNode.addBranchButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -363,8 +370,9 @@ test.describe('Any succeeded', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -375,8 +383,9 @@ test.describe('Any succeeded', () => { await twoConditionNode.submitButton.click(); // 分支3添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch3.test.ts b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch3.test.ts index bcf5ec99e..8018a9bad 100644 --- a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch3.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch3.test.ts @@ -77,8 +77,9 @@ test.describe('Any succeeded or failed', () => { await parallelBranchNode.submitButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -89,8 +90,9 @@ test.describe('Any succeeded or failed', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); @@ -198,8 +200,9 @@ test.describe('Any succeeded or failed', () => { await parallelBranchNode.submitButton.click(); // 分支1添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); @@ -210,8 +213,9 @@ test.describe('Any succeeded or failed', () => { await oneConditionNode.submitButton.click(); // 分支2添加判断节点 await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Continue when "Yes"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/src/locale/zh-CN.json b/packages/plugins/@nocobase/plugin-workflow-parallel/src/locale/zh-CN.json index 62a87c8d8..5a822552a 100644 --- a/packages/plugins/@nocobase/plugin-workflow-parallel/src/locale/zh-CN.json +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/src/locale/zh-CN.json @@ -1,5 +1,5 @@ { - "Parallel branch": "分支", + "Parallel branch": "并行分支", "Run multiple branch processes in parallel.": "并行运行多个分支流程。", "Add branch": "增加分支", "Mode": "执行模式", diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/AddButton.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/AddButton.tsx deleted file mode 100644 index c3a6d6d65..000000000 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/AddButton.tsx +++ /dev/null @@ -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(() => { - return { - onClick: onCreate, - items: compile(groups), - }; - }, [groups, onCreate]); - - if (!workflow) { - return null; - } - - return ( -
- -
- ); -} diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/AddNodeContext.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/AddNodeContext.tsx new file mode 100644 index 000000000..ee11a0f2d --- /dev/null +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/AddNodeContext.tsx @@ -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 ( +
+ +
+ ); +} + +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 ( + + ); + + // return ( + // + // + // + // ); +}); + +function PresetFieldset() { + const { presetting } = useAddNodeContext(); + if (!presetting?.instruction.presetFieldset) { + return null; + } + return ( + + ); +} + +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 ( + + {props.children} + + + + + ); +} diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/Branch.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/Branch.tsx index 35b44040a..e739c5594 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/Branch.tsx +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/Branch.tsx @@ -12,7 +12,7 @@ import { CloseOutlined } from '@ant-design/icons'; import { css, cx } from '@nocobase/client'; -import { AddButton } from './AddButton'; +import { AddButton } from './AddNodeContext'; import { useGetAriaLabelOfAddButton } from './hooks/useGetAriaLabelOfAddButton'; import { Node } from './nodes'; import useStyles from './style'; diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/CanvasContent.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/CanvasContent.tsx index 77044c9d5..6a345f959 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/CanvasContent.tsx +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/CanvasContent.tsx @@ -18,6 +18,7 @@ import { useFlowContext } from './FlowContext'; import { lang } from './locale'; import useStyles from './style'; import { TriggerConfig } from './triggers'; +import { AddNodeContextProvider } from './AddNodeContext'; export function CanvasContent({ entry }) { const { styles } = useStyles(); @@ -27,41 +28,43 @@ export function CanvasContent({ entry }) { return (
-
-
-
- {workflow?.executed ? ( - - ) : null} - -
- + +
+
+
+ {workflow?.executed ? ( + + ) : null} + +
+ +
+
{lang('End')}
-
{lang('End')}
-
+
diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType.test.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType.test.ts index b30c1338c..3b614f4f2 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType.test.ts @@ -91,8 +91,9 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -239,8 +240,9 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -383,8 +385,9 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -529,8 +532,9 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType1.test.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType1.test.ts index f7bd7e879..6f799a76e 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType1.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoBasicType1.test.ts @@ -65,8 +65,9 @@ test('Collection event add data trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -178,8 +179,9 @@ test('Collection event add data trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -291,8 +293,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -406,8 +409,9 @@ test('Collection event add data trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoFormulaEngine.test.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoFormulaEngine.test.ts index 82fad22fd..382a34ecb 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoFormulaEngine.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoFormulaEngine.test.ts @@ -68,8 +68,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -195,8 +196,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -319,8 +321,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -446,8 +449,9 @@ test('Collection event Add Data Trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -594,8 +598,9 @@ test('Collection event add data trigger, determine the trigger node integer vari await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -752,8 +757,9 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -900,8 +906,9 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -1051,8 +1058,9 @@ test('Collection event add data trigger, determine the trigger node integer vari await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoMathEngine.test.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoMathEngine.test.ts index 4d62cf7ba..9f22784b7 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoMathEngine.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/BranchIntoYesAndNoMathEngine.test.ts @@ -65,8 +65,9 @@ test('Collection event add data trigger, determine trigger node integer field va await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -189,8 +190,9 @@ test('Collection event Add Data Trigger, determines that the trigger node intege await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -310,8 +312,9 @@ test('Collection event Add Data Trigger, determines that the trigger node intege await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); @@ -431,8 +434,9 @@ test('Collection event add data trigger, determines that the trigger node intege await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('branch').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByText('Branch into "Yes" and "No"').click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionBranchNode(page, conditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesBasicType.test.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesBasicType.test.ts index d03966fb5..885a15cb2 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesBasicType.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesBasicType.test.ts @@ -69,8 +69,8 @@ test('Collection event add data trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -152,8 +152,8 @@ test('Collection event add data trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -236,8 +236,8 @@ test('Collection event Add Data Trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -322,8 +322,8 @@ test('Collection event add data trigger, determines that the trigger node single await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -432,8 +432,8 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -546,8 +546,8 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -657,8 +657,8 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -773,8 +773,8 @@ test('Collection event add data trigger, determine trigger node integer variable await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesFormulaEngine.test.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesFormulaEngine.test.ts index 607f5e44e..0c9e72a62 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesFormulaEngine.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesFormulaEngine.test.ts @@ -67,8 +67,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -157,8 +157,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -248,8 +248,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -337,8 +337,8 @@ test('Collection event Add Data Trigger, Formula engine, determines that the tri await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -452,8 +452,8 @@ test('Collection event add data trigger, Formula engine, determine the trigger n await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -570,8 +570,8 @@ test('Collection event add data trigger, Formula engine, determine trigger node await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -686,8 +686,8 @@ test('Collection event add data trigger, Formula engine, determine trigger node await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -804,8 +804,8 @@ test('Collection event add data trigger, Formula engine, determine the trigger n await page.waitForLoadState('load'); const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle); await preQueryRecordNodePom.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesMathEngine.test.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesMathEngine.test.ts index 90af5c55d..7684d89b8 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesMathEngine.test.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/__e2e__/conditionNode/continueWhenYesMathEngine.test.ts @@ -64,8 +64,8 @@ test('Collection event add data trigger, Math engine, determine trigger node int await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -155,8 +155,8 @@ test('Collection event Add Data Trigger, Math engine, determines that the trigge await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -246,8 +246,8 @@ test('Collection event Add Data Trigger, Math engine, determines that the trigge await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); @@ -336,8 +336,8 @@ test('Collection event add data trigger, Math engine, determines that the trigge await page.waitForLoadState('load'); const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName); await collectionTriggerNode.addNodeButton.click(); - await page.getByRole('button', { name: 'condition', exact: true }).hover(); - await page.getByLabel('rejectOnFalse').click(); + await page.getByRole('button', { name: 'condition', exact: true }).click(); + await page.getByLabel('action-Action-Submit-workflows').click(); const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName); const conditionNode = new ConditionYesNode(page, conditionNodeName); diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/condition.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/condition.tsx index a4c70cd44..c22382a47 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/condition.tsx +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/condition.tsx @@ -20,6 +20,12 @@ import useStyles from '../style'; import { useWorkflowVariableOptions, WorkflowVariableTextArea } from '../variable'; import { CalculationConfig } from '../components/Calculation'; +const BRANCH_INDEX = { + DEFAULT: null, + ON_TRUE: 1, + ON_FALSE: 0, +} as const; + export default class extends Instruction { title = `{{t("Condition", { ns: "${NAMESPACE}" })}}`; type = 'condition'; @@ -107,18 +113,44 @@ export default class extends Instruction { required: true, }, }; - options = [ - { - label: `{{t('Continue when "Yes"', { ns: "${NAMESPACE}" })}}`, - key: 'rejectOnFalse', - value: { rejectOnFalse: true }, + presetFieldset = { + rejectOnFalse: { + type: 'boolean', + title: `{{t("Mode", { ns: "${NAMESPACE}" })}}`, + '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', - value: { rejectOnFalse: false }, - }, - ]; + }; + + branching = ({ rejectOnFalse = true } = {}) => { + return rejectOnFalse + ? false + : [ + { + label: `{{t('After end of branches', { ns: "${NAMESPACE}" })}}`, + value: false, + }, + { + label: `{{t('Inside of "Yes" branch', { ns: "${NAMESPACE}" })}}`, + value: BRANCH_INDEX.ON_TRUE, + }, + { + label: `{{t('Inside of "No" branch', { ns: "${NAMESPACE}" })}}`, + value: BRANCH_INDEX.ON_FALSE, + }, + ]; + }; scope = { renderEngineReference, diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx index 4c8b68968..ea6a2f168 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/nodes/index.tsx @@ -34,7 +34,7 @@ import { import { parse, str2moment } from '@nocobase/utils/client'; import WorkflowPlugin from '..'; -import { AddButton } from '../AddButton'; +import { AddButton } from '../AddNodeContext'; import { useFlowContext } from '../FlowContext'; import { DrawerDescription } from '../components/DrawerDescription'; import { StatusButton } from '../components/StatusButton'; @@ -51,27 +51,40 @@ export type NodeAvailableContext = { branchIndex: number; }; +type Config = Record; + +type Options = { label: string; value: any }[]; + export abstract class Instruction { title: string; type: string; group: string; description?: string; /** - * @experimental + * @deprecated migrate to `presetFieldset` instead */ options?: { label: string; value: any; key: string }[]; fieldset: Record; + /** + * @experimental + */ + presetFieldset?: Record; + /** + * To presentation if the instruction is creating a branch + * @experimental + */ + branching?: boolean | Options | ((config: Config) => boolean | Options); /** * @experimental */ view?: ISchema; - scope?: { [key: string]: any }; - components?: { [key: string]: any }; + scope?: Record; + components?: Record; Component?(props): JSX.Element; /** * @experimental */ - createDefaultConfig?(): Record { + createDefaultConfig?(): Config { return {}; } useVariables?(node, options?: UseVariableOptions): VariableOption; @@ -243,6 +256,7 @@ export function RemoveButton() { icon={} onClick={onRemove} 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.', )} > -
-
- {lang('Unknown node')} - {data.id} +
+
+
+ {lang('Unknown node')} + {data.id} +
+
+ + +
- -
@@ -597,9 +610,15 @@ export function NodeDefaultView(props) { className={cx(styles.nodeCardClass, { configuring: editingConfig })} onClick={onOpenDrawer} > -
- {typeTitle} - {data.id} +
+
+ {typeTitle} + {data.id} +
+
+ + +
onChangeTitle(ev.target.value)} autoSize /> - - { .workflow-node-remove-button { display: none; position: absolute; - right: 0.5em; - top: 0.5em; + right: 0; + top: 0; color: ${token.colorText}; &[disabled] { @@ -312,19 +312,24 @@ const useStyles = createStyles(({ css, token }) => { nodeJobButtonClass: css` display: flex; position: absolute; - top: calc(1em - 1px); - right: 1em; + top: 0; + right: 0; justify-content: center; align-items: center; color: ${token.colorTextLightSolid}; `, nodeHeaderClass: css` - position: relative; + display: flex; + margin-bottom: 0.5em; + + .workflow-node-actions { + position: relative; + } `, nodeMetaClass: css` - margin-bottom: 0.5em; + flex-grow: 1; .workflow-node-id { color: ${token.colorTextDescription}; @@ -352,7 +357,6 @@ const useStyles = createStyles(({ css, token }) => { `, nodeJobResultClass: css` - padding: 1em; background-color: #f3f3f3; `, diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/index.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/index.tsx index 358cc8cf8..5a6af1e0a 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/index.tsx +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/index.tsx @@ -240,8 +240,10 @@ export const TriggerConfig = () => { className={cx(styles.nodeCardClass, 'invalid')} onClick={onOpenDrawer} > -
- {lang('Unknown trigger')} +
+
+ {lang('Unknown trigger')} +
@@ -260,11 +262,16 @@ export const TriggerConfig = () => { className={cx(styles.nodeCardClass)} onClick={onOpenDrawer} > -
- - - {compile(trigger.title)} - +
+
+ + + {compile(trigger.title)} + +
+
+ +
{ disabled={workflow.executed} />
-