mirror of
https://github.com/langgenius/dify.git
synced 2026-06-16 22:11:09 +08:00
fix(workflow): clamp file list upload limit (#37474)
This commit is contained in:
parent
6f31e9ef8d
commit
30506f7221
@ -11,6 +11,7 @@ type VarReferencePickerProps = {
|
||||
}
|
||||
|
||||
let lastVarReferencePickerProps: VarReferencePickerProps | undefined
|
||||
let fileUploadSettingMaxLength: number | undefined = 4
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/variable/var-reference-picker', () => ({
|
||||
default: (props: VarReferencePickerProps) => {
|
||||
@ -66,7 +67,7 @@ vi.mock('@/app/components/workflow/nodes/_base/components/file-upload-setting',
|
||||
allowed_file_extensions: ['.pdf'],
|
||||
allowed_file_types: [SupportUploadFileTypes.document],
|
||||
allowed_file_upload_methods: [TransferMethod.local_file],
|
||||
max_length: 4,
|
||||
max_length: fileUploadSettingMaxLength,
|
||||
})}
|
||||
>
|
||||
file-upload-setting
|
||||
@ -89,6 +90,7 @@ describe('InputField', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
lastVarReferencePickerProps = undefined
|
||||
fileUploadSettingMaxLength = 4
|
||||
})
|
||||
|
||||
it('should keep the header and actions visible while the field content scrolls internally', () => {
|
||||
@ -627,6 +629,32 @@ describe('InputField', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should normalize empty file-list upload limit on save', async () => {
|
||||
const user = userEvent.setup()
|
||||
const onChange = vi.fn()
|
||||
fileUploadSettingMaxLength = Number.NaN
|
||||
|
||||
render(
|
||||
<InputField
|
||||
nodeId="node-14-normalize"
|
||||
isEdit={false}
|
||||
payload={createPayload()}
|
||||
onChange={onChange}
|
||||
onCancel={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'select-file-list' }))
|
||||
await user.click(screen.getByRole('button', { name: 'file-upload-setting' }))
|
||||
await user.click(screen.getByRole('button', { name: /workflow\.nodes\.humanInput\.insertInputField\.insert/i }))
|
||||
|
||||
expect(onChange).toHaveBeenCalledTimes(1)
|
||||
expect(onChange.mock.calls[0]![0]).toEqual(expect.objectContaining({
|
||||
type: InputVarType.multiFiles,
|
||||
number_limits: 1,
|
||||
}))
|
||||
})
|
||||
|
||||
it('should clear paragraph default state when switching to file-list', async () => {
|
||||
const user = userEvent.setup()
|
||||
const onChange = vi.fn()
|
||||
|
||||
@ -97,6 +97,16 @@ const InputField: React.FC<InputFieldProps> = ({
|
||||
const handleSave = useCallback(() => {
|
||||
if (!nameValid)
|
||||
return
|
||||
if (isFileListFormInput(tempPayload)) {
|
||||
const value = tempPayload.number_limits ?? 5
|
||||
if (!Number.isFinite(value)) {
|
||||
onChange({
|
||||
...tempPayload,
|
||||
number_limits: 1,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
onChange(tempPayload)
|
||||
}, [nameValid, onChange, tempPayload])
|
||||
const handleTypeChange = useCallback((item: TypeSelectItem) => {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { UploadFileSetting } from '@/app/components/workflow/types'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { useState } from 'react'
|
||||
import { useFileSizeLimit } from '@/app/components/base/file-uploader/hooks'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
import { useFileUploadConfig } from '@/service/use-common'
|
||||
@ -120,6 +121,35 @@ describe('File upload support components', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('should keep upload limits within the configured range', () => {
|
||||
const StatefulFileUploadSetting = () => {
|
||||
const [payload, setPayload] = useState(createPayload())
|
||||
|
||||
return (
|
||||
<FileUploadSetting
|
||||
payload={payload}
|
||||
isMultiple
|
||||
onChange={setPayload}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
render(<StatefulFileUploadSetting />)
|
||||
|
||||
const input = screen.getByRole('spinbutton')
|
||||
|
||||
fireEvent.change(input, { target: { value: '20' } })
|
||||
expect(input).toHaveValue(10)
|
||||
|
||||
fireEvent.change(input, { target: { value: '0' } })
|
||||
expect(input).toHaveValue(1)
|
||||
|
||||
fireEvent.change(input, { target: { value: '' } })
|
||||
expect(input).toHaveValue(null)
|
||||
fireEvent.blur(input)
|
||||
expect(input).toHaveValue(1)
|
||||
})
|
||||
|
||||
it('should toggle built-in and custom file type selections', async () => {
|
||||
const user = userEvent.setup()
|
||||
const onChange = vi.fn()
|
||||
|
||||
@ -89,11 +89,14 @@ const FileUploadSetting: FC<Props> = ({
|
||||
}, [onChange, payload])
|
||||
|
||||
const handleMaxUploadNumLimitChange = useCallback((value: number) => {
|
||||
const normalizedValue = Number.isFinite(value)
|
||||
? Math.min(Math.max(value, 1), maxFileUploadLimit)
|
||||
: value
|
||||
const newPayload = produce(payload, (draft) => {
|
||||
draft.max_length = value
|
||||
draft.max_length = normalizedValue
|
||||
})
|
||||
onChange(newPayload)
|
||||
}, [onChange, payload])
|
||||
}, [maxFileUploadLimit, onChange, payload])
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -163,6 +166,7 @@ const FileUploadSetting: FC<Props> = ({
|
||||
<InputNumberWithSlider
|
||||
label={t('variableConfig.maxNumberOfUploads', { ns: 'appDebug' })!}
|
||||
value={max_length}
|
||||
defaultValue={1}
|
||||
min={1}
|
||||
max={maxFileUploadLimit}
|
||||
onChange={handleMaxUploadNumLimitChange}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user