refactor(web): migrate loop variable constant inputs (#41901)

This commit is contained in:
yyh 2026-09-07 04:15:41 +00:00 committed by GitHub
parent 789cada297
commit 3e961dbb77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 74 additions and 14 deletions

View File

@ -4001,11 +4001,8 @@
}
},
"web/app/components/workflow/nodes/loop/components/loop-variables/form-item.tsx": {
"no-restricted-imports": {
"count": 1
},
"typescript/no-explicit-any": {
"count": 3
"count": 2
}
},
"web/app/components/workflow/nodes/loop/components/loop-variables/item.tsx": {

View File

@ -0,0 +1,62 @@
import type { LoopVariable } from '@/app/components/workflow/nodes/loop/types'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useState } from 'react'
import { ValueType, VarType } from '@/app/components/workflow/types'
import FormItem from '../form-item'
describe('Loop variable constant input', () => {
it('reports numeric edits and clearing as strings to the loop draft', async () => {
const user = userEvent.setup()
const onChange = vi.fn()
function LoopDraft() {
const [value, setValue] = useState('12')
return (
<FormItem
nodeId="loop-node"
item={{
id: 'count',
label: 'count',
var_type: VarType.number,
value_type: ValueType.constant,
value,
}}
onChange={(nextValue) => {
setValue(nextValue)
onChange(nextValue)
}}
/>
)
}
render(<LoopDraft />)
const input = screen.getByRole('spinbutton', { name: 'count' })
await user.clear(input)
expect(onChange).toHaveBeenLastCalledWith('')
await user.type(input, '-3.5')
expect(input).toHaveValue(-3.5)
expect(onChange).toHaveBeenLastCalledWith('-3.5')
})
it.each([
[VarType.number, 'spinbutton'],
[VarType.string, 'textbox'],
] as const)('names an unnamed %s constant until its variable is named', (varType, role) => {
const item: LoopVariable = {
id: 'new-variable',
label: '',
var_type: varType,
value_type: ValueType.constant,
value: '',
}
const { rerender } = render(<FormItem nodeId="loop-node" item={item} onChange={vi.fn()} />)
expect(
screen.getByRole(role, { name: 'workflow.errorMsg.fields.variableValue' }),
).toBeInTheDocument()
rerender(
<FormItem nodeId="loop-node" item={{ ...item, label: 'counter' }} onChange={vi.fn()} />,
)
expect(screen.getByRole(role, { name: 'counter' })).toBeInTheDocument()
})
})

View File

@ -1,9 +1,9 @@
import type { LoopVariable } from '@/app/components/workflow/nodes/loop/types'
import type { Var } from '@/app/components/workflow/types'
import { Input } from '@langgenius/dify-ui/input'
import { Textarea } from '@langgenius/dify-ui/textarea'
import { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
@ -26,17 +26,11 @@ type FormItemProps = {
const FormItem = ({ nodeId, item, onChange }: FormItemProps) => {
const { t } = useTranslation()
const { value_type, var_type, value } = item
const valueLabel = item.label || t(($) => $['errorMsg.fields.variableValue'], { ns: 'workflow' })
const normalizedVarValue = useMemo(() => {
return Array.isArray(value) ? value : []
}, [value])
const handleInputChange = useCallback(
(e: any) => {
onChange(e.target.value)
},
[onChange],
)
const handleValueChange = useCallback(
(value: string) => {
onChange(value)
@ -85,14 +79,21 @@ const FormItem = ({ nodeId, item, onChange }: FormItemProps) => {
)}
{value_type === ValueType.constant && var_type === VarType.string && (
<Textarea
aria-label={item.label}
aria-label={valueLabel}
value={value}
onValueChange={handleValueChange}
className="min-h-12 w-full"
/>
)}
{value_type === ValueType.constant && var_type === VarType.number && (
<Input type="number" value={value} onChange={handleInputChange} className="w-full" />
<Input
aria-label={valueLabel}
type="number"
value={value}
onValueChange={handleValueChange}
placeholder={t(($) => $['placeholder.input'], { ns: 'common' })}
className="w-full"
/>
)}
{value_type === ValueType.constant && var_type === VarType.boolean && (
<BoolValue value={value} onChange={handleChange} />