mirror of
https://github.com/langgenius/dify.git
synced 2026-05-12 15:58:19 +08:00
fix(web): form in email test sender
This commit is contained in:
parent
d65cc21e85
commit
a9de4bd96b
@ -286,6 +286,9 @@ describe('human-input/panel', () => {
|
||||
availableVars: [{
|
||||
variable: ['start', 'email'],
|
||||
type: VarType.string,
|
||||
}, {
|
||||
variable: ['code', 'result'],
|
||||
type: VarType.arrayString,
|
||||
}, {
|
||||
variable: ['start', 'files'],
|
||||
type: VarType.file,
|
||||
@ -314,6 +317,12 @@ describe('human-input/panel', () => {
|
||||
expect(screen.getByText('review_result:string:Form input value')).toBeInTheDocument()
|
||||
expect(screen.getByText('__action_id:string:Action ID user triggered')).toBeInTheDocument()
|
||||
expect(screen.getByText('__rendered_content:string:Rendered content')).toBeInTheDocument()
|
||||
expect(mockDeliveryMethod).toHaveBeenCalledWith(expect.objectContaining({
|
||||
nodesOutputVars: [
|
||||
expect.objectContaining({ type: VarType.string }),
|
||||
expect.objectContaining({ type: VarType.arrayString }),
|
||||
],
|
||||
}))
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'delivery-method:editable' }))
|
||||
await user.click(screen.getByRole('button', { name: /workflow\.nodes\.humanInput\.formContent\.preview/ }))
|
||||
|
||||
@ -2,7 +2,7 @@ import type { ReactNode } from 'react'
|
||||
import type { EmailConfig, FormInputItem } from '../../../types'
|
||||
import type { App, AppSSO } from '@/types/app'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { HooksStoreContext } from '@/app/components/workflow/hooks-store/provider'
|
||||
@ -161,7 +161,7 @@ const createDynamicSelectInput = (): FormInputItem => ({
|
||||
output_variable_name: 'decision',
|
||||
option_source: {
|
||||
type: 'variable',
|
||||
selector: ['start', 'choices'],
|
||||
selector: ['code', 'result'],
|
||||
value: [],
|
||||
},
|
||||
})
|
||||
@ -243,7 +243,7 @@ describe('human-input/delivery-method/test-email-sender', () => {
|
||||
delivery_method_id: 'delivery-1',
|
||||
inputs: {
|
||||
'#start.user_name#': 'Ada',
|
||||
'#start.score#': '42',
|
||||
'#start.score#': 42,
|
||||
},
|
||||
},
|
||||
}))
|
||||
@ -270,23 +270,32 @@ describe('human-input/delivery-method/test-email-sender', () => {
|
||||
formInputs={[createDynamicSelectInput()]}
|
||||
availableNodes={[
|
||||
{
|
||||
id: 'start',
|
||||
id: 'code',
|
||||
type: 'custom',
|
||||
position: { x: 0, y: 0 },
|
||||
data: {
|
||||
title: 'Start',
|
||||
title: 'Code',
|
||||
desc: '',
|
||||
type: BlockEnum.Start,
|
||||
type: BlockEnum.Code,
|
||||
variables: [],
|
||||
code_language: 'python3',
|
||||
code: '',
|
||||
outputs: {
|
||||
result: {
|
||||
type: VarType.arrayString,
|
||||
children: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
nodesOutputVars={[
|
||||
{
|
||||
nodeId: 'start',
|
||||
title: 'Start',
|
||||
nodeId: 'code',
|
||||
title: 'Code',
|
||||
vars: [
|
||||
{
|
||||
variable: 'choices',
|
||||
variable: 'result',
|
||||
type: VarType.arrayString,
|
||||
},
|
||||
],
|
||||
@ -298,7 +307,11 @@ describe('human-input/delivery-method/test-email-sender', () => {
|
||||
const sendButton = screen.getByRole('button', { name: 'workflow.nodes.humanInput.deliveryMethod.emailSender.send' })
|
||||
expect(sendButton).toBeDisabled()
|
||||
|
||||
await user.type(screen.getByPlaceholderText('choices'), 'approve,reject')
|
||||
expect(screen.queryByPlaceholderText('result')).not.toBeInTheDocument()
|
||||
|
||||
fireEvent.change(screen.getByTestId('monaco-editor'), {
|
||||
target: { value: '["approve","reject"]' },
|
||||
})
|
||||
expect(sendButton).toBeEnabled()
|
||||
|
||||
await user.click(sendButton)
|
||||
@ -309,7 +322,7 @@ describe('human-input/delivery-method/test-email-sender', () => {
|
||||
body: {
|
||||
delivery_method_id: 'delivery-1',
|
||||
inputs: {
|
||||
'#start.choices#': 'approve,reject',
|
||||
'#code.result#': ['approve', 'reject'],
|
||||
},
|
||||
},
|
||||
})))
|
||||
|
||||
@ -7,6 +7,7 @@ import type {
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { RiArrowRightSFill } from '@remixicon/react'
|
||||
import { noop, unionBy } from 'es-toolkit/compat'
|
||||
import { memo, useCallback, useMemo, useState } from 'react'
|
||||
@ -15,6 +16,7 @@ import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { getInputVars as doGetInputVars } from '@/app/components/base/prompt-editor/constants'
|
||||
import FormItem from '@/app/components/workflow/nodes/_base/components/before-run-form/form-item'
|
||||
import { formatValue } from '@/app/components/workflow/nodes/_base/components/before-run-form/helpers'
|
||||
import {
|
||||
getNodeInfoById,
|
||||
isConversationVar,
|
||||
@ -69,6 +71,45 @@ const getOriginVar = (valueSelector: string[], list: NodeOutPutVar[]) => {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const varTypeToInputVarType = (type: VarType) => {
|
||||
if (type === VarType.number)
|
||||
return InputVarType.number
|
||||
if (type === VarType.boolean)
|
||||
return InputVarType.checkbox
|
||||
if ([VarType.object, VarType.array, VarType.arrayNumber, VarType.arrayString, VarType.arrayObject].includes(type))
|
||||
return InputVarType.json
|
||||
if (type === VarType.file)
|
||||
return InputVarType.singleFile
|
||||
if (type === VarType.arrayFile)
|
||||
return InputVarType.multiFiles
|
||||
|
||||
return InputVarType.textInput
|
||||
}
|
||||
|
||||
const formatEmailSenderInputs = (
|
||||
variables: Array<{ variable: string, type: InputVarType, label: unknown }>,
|
||||
values: Record<string, unknown>,
|
||||
) => {
|
||||
const formattedValues: Record<string, unknown> = {}
|
||||
let parseErrorJsonField = ''
|
||||
|
||||
variables.forEach((variable) => {
|
||||
try {
|
||||
formattedValues[variable.variable] = formatValue(values[variable.variable], variable.type)
|
||||
}
|
||||
catch {
|
||||
parseErrorJsonField = typeof variable.label === 'object' && variable.label !== null && 'variable' in variable.label
|
||||
? String(variable.label.variable)
|
||||
: variable.variable
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
formattedValues,
|
||||
parseErrorJsonField,
|
||||
}
|
||||
}
|
||||
|
||||
const EmailSenderModal = ({
|
||||
nodeId,
|
||||
deliveryId,
|
||||
@ -126,7 +167,7 @@ const EmailSenderModal = ({
|
||||
return {
|
||||
label: item.label || item.variable,
|
||||
variable: item.variable,
|
||||
type: originalVar.type === VarType.number ? InputVarType.number : InputVarType.textInput,
|
||||
type: varTypeToInputVarType(originalVar.type),
|
||||
required: true,
|
||||
}
|
||||
})
|
||||
@ -160,20 +201,25 @@ const EmailSenderModal = ({
|
||||
const handleConfirm = useCallback(async () => {
|
||||
if (!confirmChecked)
|
||||
return
|
||||
const { formattedValues, parseErrorJsonField } = formatEmailSenderInputs(generatedInputs, inputs)
|
||||
if (parseErrorJsonField) {
|
||||
toast.error(t('errorMsg.invalidJson', { ns: 'workflow', field: parseErrorJsonField }))
|
||||
return
|
||||
}
|
||||
setSendingEmail(true)
|
||||
try {
|
||||
await testEmailSender({
|
||||
appID: appDetail?.id || '',
|
||||
nodeID: nodeId,
|
||||
deliveryID: deliveryId,
|
||||
inputs,
|
||||
inputs: formattedValues,
|
||||
})
|
||||
setDone(true)
|
||||
}
|
||||
finally {
|
||||
setSendingEmail(false)
|
||||
}
|
||||
}, [confirmChecked, testEmailSender, appDetail?.id, nodeId, deliveryId, inputs])
|
||||
}, [confirmChecked, generatedInputs, inputs, testEmailSender, appDetail?.id, nodeId, deliveryId, t])
|
||||
|
||||
if (done) {
|
||||
return (
|
||||
|
||||
@ -69,7 +69,7 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
const { availableVars, availableNodesWithParent } = useAvailableVarList(id, {
|
||||
onlyLeafNodeVar: false,
|
||||
filterVar: (varPayload: Var) => {
|
||||
return [VarType.string, VarType.number, VarType.secret].includes(varPayload.type)
|
||||
return [VarType.string, VarType.number, VarType.secret, VarType.arrayString].includes(varPayload.type)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user