fix: remove hardcoded 48-character limit from text inputs (#30156)

Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
This commit is contained in:
lif 2026-01-15 17:43:00 +08:00 committed by GitHub
parent 4a197b9458
commit 2b021e8752
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 52 additions and 47 deletions

View File

@ -21,7 +21,6 @@ import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/
import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import { ChangeType, InputVarType, SupportUploadFileTypes } from '@/app/components/workflow/types'
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import ConfigContext from '@/context/debug-configuration'
import { AppModeEnum, TransferMethod } from '@/types/app'
import { checkKeys, getNewVarInWorkflow, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
@ -198,8 +197,6 @@ const ConfigModal: FC<IConfigModalProps> = ({
if (type === InputVarType.multiFiles)
draft.max_length = DEFAULT_FILE_UPLOAD_SETTING.max_length
}
if (type === InputVarType.paragraph)
draft.max_length = DEFAULT_VALUE_MAX_LEN
})
setTempPayload(newPayload)
}, [tempPayload])

View File

@ -15,7 +15,6 @@ import Confirm from '@/app/components/base/confirm'
import Toast from '@/app/components/base/toast'
import Tooltip from '@/app/components/base/tooltip'
import { InputVarType } from '@/app/components/workflow/types'
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import ConfigContext from '@/context/debug-configuration'
import { useEventEmitterContextContext } from '@/context/event-emitter'
import { useModalContext } from '@/context/modal-context'
@ -58,8 +57,6 @@ const buildPromptVariableFromInput = (payload: InputVar): PromptVariable => {
key: variable,
name: label as string,
}
if (payload.type === InputVarType.textInput)
nextItem.max_length = nextItem.max_length || DEFAULT_VALUE_MAX_LEN
if (payload.type !== InputVarType.select)
delete nextItem.options

View File

@ -7,7 +7,6 @@ import Input from '@/app/components/base/input'
import Select from '@/app/components/base/select'
import Textarea from '@/app/components/base/textarea'
import BoolInput from '@/app/components/workflow/nodes/_base/components/before-run-form/bool-input'
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import ConfigContext from '@/context/debug-configuration'
import { cn } from '@/utils/classnames'
@ -88,7 +87,7 @@ const ChatUserInput = ({
onChange={(e) => { handleInputValueChange(key, e.target.value) }}
placeholder={name}
autoFocus={index === 0}
maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
maxLength={max_length}
/>
)}
{type === 'paragraph' && (
@ -115,7 +114,7 @@ const ChatUserInput = ({
onChange={(e) => { handleInputValueChange(key, e.target.value) }}
placeholder={name}
autoFocus={index === 0}
maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
maxLength={max_length}
/>
)}
{type === 'checkbox' && (

View File

@ -20,7 +20,6 @@ import Select from '@/app/components/base/select'
import Textarea from '@/app/components/base/textarea'
import Tooltip from '@/app/components/base/tooltip'
import BoolInput from '@/app/components/workflow/nodes/_base/components/before-run-form/bool-input'
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import ConfigContext from '@/context/debug-configuration'
import { AppModeEnum, ModelModeType } from '@/types/app'
import { cn } from '@/utils/classnames'
@ -142,7 +141,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
onChange={(e) => { handleInputValueChange(key, e.target.value) }}
placeholder={name}
autoFocus={index === 0}
maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
maxLength={max_length}
/>
)}
{type === 'paragraph' && (
@ -170,7 +169,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
onChange={(e) => { handleInputValueChange(key, e.target.value) }}
placeholder={name}
autoFocus={index === 0}
maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
maxLength={max_length}
/>
)}
{type === 'checkbox' && (

View File

@ -6,7 +6,6 @@ import { useTranslation } from 'react-i18next'
import { useFileSizeLimit } from '@/app/components/base/file-uploader/hooks'
import { InputFieldType } from '@/app/components/base/form/form-scenarios/input-field/types'
import { DEFAULT_FILE_UPLOAD_SETTING } from '@/app/components/workflow/constants'
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import { PipelineInputVarType } from '@/models/pipeline'
import { useFileUploadConfig } from '@/service/use-common'
import { formatFileSize } from '@/utils/format'
@ -87,8 +86,6 @@ export const useConfigurations = (props: {
if (type === PipelineInputVarType.multiFiles)
setFieldValue('maxLength', DEFAULT_FILE_UPLOAD_SETTING.max_length)
}
if (type === PipelineInputVarType.paragraph)
setFieldValue('maxLength', DEFAULT_VALUE_MAX_LEN)
}, [setFieldValue])
const handleVariableNameBlur = useCallback((value: string) => {

View File

@ -779,27 +779,6 @@ describe('useConfigurations', () => {
expect(mockSetFieldValue).toHaveBeenCalledWith('maxLength', expect.any(Number))
})
it('should call setFieldValue when type changes to paragraph', () => {
// Arrange
const mockGetFieldValue = vi.fn()
const mockSetFieldValue = vi.fn()
const { result } = renderHookWithProviders(() =>
useConfigurations({
getFieldValue: mockGetFieldValue,
setFieldValue: mockSetFieldValue,
supportFile: false,
}),
)
// Act
const typeConfig = result.current.find(config => config.variable === 'type')
typeConfig?.listeners?.onChange?.(createMockEvent(PipelineInputVarType.paragraph))
// Assert
expect(mockSetFieldValue).toHaveBeenCalledWith('maxLength', 48) // DEFAULT_VALUE_MAX_LEN
})
it('should set label from variable name on blur when label is empty', () => {
// Arrange
const mockGetFieldValue = vi.fn().mockReturnValue('')

View File

@ -26,7 +26,7 @@ import DifyLogo from '@/app/components/base/logo/dify-logo'
import Toast from '@/app/components/base/toast'
import Res from '@/app/components/share/text-generation/result'
import RunOnce from '@/app/components/share/text-generation/run-once'
import { appDefaultIconBackground, BATCH_CONCURRENCY, DEFAULT_VALUE_MAX_LEN } from '@/config'
import { appDefaultIconBackground, BATCH_CONCURRENCY } from '@/config'
import { useGlobalPublicStore } from '@/context/global-public-context'
import { useWebAppStore } from '@/context/web-app-context'
import { useAppFavicon } from '@/hooks/use-app-favicon'
@ -256,11 +256,10 @@ const TextGeneration: FC<IMainProps> = ({
promptConfig?.prompt_variables.forEach((varItem, varIndex) => {
if (errorRowIndex !== 0)
return
if (varItem.type === 'string') {
const maxLen = varItem.max_length || DEFAULT_VALUE_MAX_LEN
if (item[varIndex].length > maxLen) {
if (varItem.type === 'string' && varItem.max_length) {
if (item[varIndex].length > varItem.max_length) {
moreThanMaxLengthVarName = varItem.name
maxLength = maxLen
maxLength = varItem.max_length
errorRowIndex = index + 1
return
}

View File

@ -236,4 +236,46 @@ describe('RunOnce', () => {
const stopButton = screen.getByTestId('stop-button')
expect(stopButton).toBeDisabled()
})
describe('maxLength behavior', () => {
it('should not have maxLength attribute when max_length is not set', async () => {
const promptConfig: PromptConfig = {
prompt_template: 'template',
prompt_variables: [
createPromptVariable({
key: 'textInput',
name: 'Text Input',
type: 'string',
// max_length is not set
}),
],
}
const { onInputsChange } = setup({ promptConfig, visionConfig: { ...baseVisionConfig, enabled: false } })
await waitFor(() => {
expect(onInputsChange).toHaveBeenCalled()
})
const input = screen.getByPlaceholderText('Text Input')
expect(input).not.toHaveAttribute('maxLength')
})
it('should have maxLength attribute when max_length is set', async () => {
const promptConfig: PromptConfig = {
prompt_template: 'template',
prompt_variables: [
createPromptVariable({
key: 'textInput',
name: 'Text Input',
type: 'string',
max_length: 100,
}),
],
}
const { onInputsChange } = setup({ promptConfig, visionConfig: { ...baseVisionConfig, enabled: false } })
await waitFor(() => {
expect(onInputsChange).toHaveBeenCalled()
})
const input = screen.getByPlaceholderText('Text Input')
expect(input).toHaveAttribute('maxLength', '100')
})
})
})

View File

@ -19,7 +19,6 @@ import Textarea from '@/app/components/base/textarea'
import BoolInput from '@/app/components/workflow/nodes/_base/components/before-run-form/bool-input'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { cn } from '@/utils/classnames'
@ -140,7 +139,7 @@ const RunOnce: FC<IRunOnceProps> = ({
placeholder={item.name}
value={inputs[item.key]}
onChange={(e: ChangeEvent<HTMLInputElement>) => { handleInputsChange({ ...inputsRef.current, [item.key]: e.target.value }) }}
maxLength={item.max_length || DEFAULT_VALUE_MAX_LEN}
maxLength={item.max_length}
/>
)}
{item.type === 'paragraph' && (

View File

@ -208,7 +208,6 @@ export const VAR_ITEM_TEMPLATE = {
key: '',
name: '',
type: 'string',
max_length: DEFAULT_VALUE_MAX_LEN,
required: true,
}
@ -216,7 +215,6 @@ export const VAR_ITEM_TEMPLATE_IN_WORKFLOW = {
variable: '',
label: '',
type: InputVarType.textInput,
max_length: DEFAULT_VALUE_MAX_LEN,
required: true,
options: [],
}
@ -225,7 +223,6 @@ export const VAR_ITEM_TEMPLATE_IN_PIPELINE = {
variable: '',
label: '',
type: PipelineInputVarType.textInput,
max_length: DEFAULT_VALUE_MAX_LEN,
required: true,
options: [],
}

View File

@ -30,7 +30,7 @@ export const getNewVar = (key: string, type: string) => {
}
export const getNewVarInWorkflow = (key: string, type = InputVarType.textInput): InputVar => {
const { max_length: _maxLength, ...rest } = VAR_ITEM_TEMPLATE_IN_WORKFLOW
const { ...rest } = VAR_ITEM_TEMPLATE_IN_WORKFLOW
if (type !== InputVarType.textInput) {
return {
...rest,