From 23d39beeed355962fa14672d7e91c948189eda9d Mon Sep 17 00:00:00 2001 From: JzoNg Date: Fri, 8 May 2026 10:41:55 +0800 Subject: [PATCH] fix(web): add email configuration check in human input node --- .../__tests__/human-input.spec.tsx | 50 +++++++++++++++++++ .../workflow/nodes/human-input/default.ts | 27 +++++++++- web/i18n/en-US/workflow.json | 1 + web/i18n/zh-Hans/workflow.json | 1 + 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/web/app/components/workflow/nodes/human-input/__tests__/human-input.spec.tsx b/web/app/components/workflow/nodes/human-input/__tests__/human-input.spec.tsx index 2ce63d5c4d..c5d88ad654 100644 --- a/web/app/components/workflow/nodes/human-input/__tests__/human-input.spec.tsx +++ b/web/app/components/workflow/nodes/human-input/__tests__/human-input.spec.tsx @@ -444,6 +444,56 @@ describe('DSL Import with Human Input Node', () => { expect(result.isValid).toBe(false) }) + it('should validate that enabled email delivery methods have complete configuration', () => { + const t = (key: string) => key + const payload = { + ...humanInputDefault.defaultValue, + delivery_methods: [ + { + id: 'dm-email', + type: DeliveryMethodType.Email, + enabled: true, + }, + ], + user_actions: [ + { id: 'approve', title: 'Approve', button_style: UserActionButtonType.Primary }, + ], + } as HumanInputNodeType + + const result = humanInputDefault.checkValid(payload, t) + + expect(result.isValid).toBe(false) + expect(result.errorMessage).toBe('nodes.humanInput.errorMsg.emailConfigIncomplete') + }) + + it('should validate email delivery config fields before user actions', () => { + const t = (key: string) => key + const payload = { + ...humanInputDefault.defaultValue, + delivery_methods: [ + { + id: 'dm-email', + type: DeliveryMethodType.Email, + enabled: true, + config: { + recipients: { whole_workspace: false, items: [] }, + subject: 'Review request', + body: 'Please review {{#url#}}', + debug_mode: false, + }, + }, + ], + user_actions: [ + { id: 'approve', title: 'Approve', button_style: UserActionButtonType.Primary }, + ], + } as HumanInputNodeType + + const result = humanInputDefault.checkValid(payload, t) + + expect(result.isValid).toBe(false) + expect(result.errorMessage).toBe('nodes.humanInput.errorMsg.emailConfigIncomplete') + }) + it('should validate that user actions are required', () => { const t = (key: string) => key const payload = { diff --git a/web/app/components/workflow/nodes/human-input/default.ts b/web/app/components/workflow/nodes/human-input/default.ts index 196f3f840b..15b228bd73 100644 --- a/web/app/components/workflow/nodes/human-input/default.ts +++ b/web/app/components/workflow/nodes/human-input/default.ts @@ -1,8 +1,9 @@ import type { NodeDefault, Var } from '../../types' -import type { FormInputItem, HumanInputNodeType } from './types' +import type { DeliveryMethod, EmailConfig, FormInputItem, HumanInputNodeType } from './types' import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types' import { BlockEnum, VarType } from '@/app/components/workflow/types' import { genNodeMetaData } from '@/app/components/workflow/utils' +import { DeliveryMethodType } from './types' const i18nPrefix = 'nodes.humanInput.errorMsg' @@ -31,6 +32,27 @@ const buildOutputVars = (inputs: FormInputItem[]): Var[] => { }) } +const isEmailConfigComplete = (config?: EmailConfig): boolean => { + if (!config) + return false + + if (!config.subject?.trim() || !config.body?.trim()) + return false + + if (!/\{\{#url#\}\}/.test(config.body.trim())) + return false + + return !!config.recipients?.whole_workspace || !!config.recipients?.items?.length +} + +const hasIncompleteEnabledEmailConfig = (deliveryMethods: DeliveryMethod[]): boolean => { + return deliveryMethods.some((method) => { + return method.enabled + && method.type === DeliveryMethodType.Email + && !isEmailConfigComplete(method.config) + }) +} + const nodeDefault: NodeDefault = { metaData, defaultValue: { @@ -49,6 +71,9 @@ const nodeDefault: NodeDefault = { if (!errorMessages && payload.delivery_methods.length > 0 && !payload.delivery_methods.some(method => method.enabled)) errorMessages = t(`${i18nPrefix}.noDeliveryMethodEnabled`, { ns: 'workflow' }) + if (!errorMessages && hasIncompleteEnabledEmailConfig(payload.delivery_methods)) + errorMessages = t(`${i18nPrefix}.emailConfigIncomplete`, { ns: 'workflow' }) + if (!errorMessages && !payload.user_actions.length) errorMessages = t(`${i18nPrefix}.noUserActions`, { ns: 'workflow' }) diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json index d1c6bf8e5a..f698d62ba3 100644 --- a/web/i18n/en-US/workflow.json +++ b/web/i18n/en-US/workflow.json @@ -613,6 +613,7 @@ "nodes.humanInput.deliveryMethod.upgradeTipHide": "Dismiss", "nodes.humanInput.editor.previewTip": "In preview mode, action buttons are not functional.", "nodes.humanInput.errorMsg.duplicateActionId": "Duplicate action ID found in user actions", + "nodes.humanInput.errorMsg.emailConfigIncomplete": "Please complete the Email delivery method configuration", "nodes.humanInput.errorMsg.emptyActionId": "Action ID cannot be empty", "nodes.humanInput.errorMsg.emptyActionTitle": "Action title cannot be empty", "nodes.humanInput.errorMsg.noDeliveryMethod": "Please select at least one delivery method", diff --git a/web/i18n/zh-Hans/workflow.json b/web/i18n/zh-Hans/workflow.json index cc164c86ec..02a83fa6a6 100644 --- a/web/i18n/zh-Hans/workflow.json +++ b/web/i18n/zh-Hans/workflow.json @@ -613,6 +613,7 @@ "nodes.humanInput.deliveryMethod.upgradeTipHide": "关闭", "nodes.humanInput.editor.previewTip": "在预览模式下,操作按钮无法使用。", "nodes.humanInput.errorMsg.duplicateActionId": "用户操作中存在重复的操作 ID", + "nodes.humanInput.errorMsg.emailConfigIncomplete": "请完成 Email 提交方式配置", "nodes.humanInput.errorMsg.emptyActionId": "操作 ID 不能为空", "nodes.humanInput.errorMsg.emptyActionTitle": "操作标题不能为空", "nodes.humanInput.errorMsg.noDeliveryMethod": "请至少选择一种提交方式",