Compare commits

...
Author SHA1 Message Date
JzoNg 096d7b62d6 fix(web): support file / file-list variable in form content 2026-06-08 15:46:43 +08:00
5 changed files with 42 additions and 0 deletions
@@ -6,6 +6,7 @@ import userEvent from '@testing-library/user-event'
import { describe, expect, it, vi } from 'vitest'
import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
import { useSelector } from '@/context/app-context'
import { TransferMethod } from '@/types/app'
import { UnsubmittedHumanInputContent } from '../unsubmitted'
// Mock AppContext's useSelector to control user profile data
@@ -130,6 +131,30 @@ describe('UnsubmittedHumanInputContent Integration', () => {
expect(screen.getByText('share.humanInput.expiredTip')).toBeInTheDocument()
})
it('should render files from the human input required event at the bottom of the form content', () => {
const data = createMockFormData({
files: [
{
related_id: 'file-1',
extension: '.pdf',
filename: 'approval.pdf',
size: 1024,
mime_type: 'application/pdf',
transfer_method: TransferMethod.local_file,
type: 'document',
url: 'https://upload.dify.ai/files/file-1',
upload_file_id: 'file-1',
remote_url: '',
},
],
})
render(<UnsubmittedHumanInputContent formData={data} onSubmit={vi.fn()} />)
expect(screen.getByTestId('file-list')).toBeInTheDocument()
expect(screen.getByText('approval.pdf')).toBeInTheDocument()
})
})
describe('Interactions', () => {
@@ -6,6 +6,8 @@ import type { UserAction } from '@/app/components/workflow/nodes/human-input/typ
import { Button } from '@langgenius/dify-ui/button'
import * as React from 'react'
import { useCallback, useState } from 'react'
import { FileList } from '@/app/components/base/file-uploader'
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
import ContentItem from './content-item'
import { getButtonStyle, getProcessedHumanInputFormInputs, getRenderedFormInputs, hasInvalidSelectOrFileInput, initializeInputs, splitByOutputVar } from './utils'
@@ -19,6 +21,9 @@ const HumanInputForm = ({
const defaultInputs = initializeInputs(renderedFormInputs, formData.resolved_default_values || {})
const [inputs, setInputs] = useState(defaultInputs)
const [isSubmitting, setIsSubmitting] = useState(false)
const files = formData.files?.length
? getProcessedFilesFromResponse(formData.files)
: []
const handleInputsChange = useCallback((name: string, value: HumanInputFieldValue) => {
setInputs(prev => ({
@@ -49,6 +54,15 @@ const HumanInputForm = ({
onInputChange={handleInputsChange}
/>
))}
{!!files.length && (
<FileList
className="my-1"
files={files}
showDeleteAction={false}
showDownloadAction
canPreview
/>
)}
<div className="flex flex-wrap gap-1 py-1">
{formData.actions.map((action: UserAction) => (
<Button
@@ -165,6 +165,7 @@ describe('FormContent', () => {
expect(mockPromptEditor).toHaveBeenCalledWith(expect.objectContaining({
editable: true,
isSupportFileVar: true,
shortcutPopups: [
expect.objectContaining({
hotkey: ['mod', '/'],
@@ -193,6 +193,7 @@ const FormContent: FC<FormContentProps> = ({
getVarType,
workflowNodesMap,
}}
isSupportFileVar
editable={!readonly}
shortcutPopups={shortcutPopups}
/>
+1
View File
@@ -333,6 +333,7 @@ export type HumanInputFormData = {
actions: UserAction[]
form_token: string
resolved_default_values: Record<string, HumanInputResolvedValue>
files?: FileResponse[]
display_in_ui: boolean
expiration_time: number
}