feat(variable-list): add drag-and-drop functionality for variables in code node (#22127)

This commit is contained in:
Minamiyama
2025-07-16 15:24:19 +08:00
committed by GitHub
parent d52fb18457
commit 66cc1b4308

View File

@@ -1,6 +1,6 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React, { useCallback } from 'react' import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import produce from 'immer' import produce from 'immer'
import RemoveButton from '../remove-button' import RemoveButton from '../remove-button'
@@ -10,6 +10,10 @@ import type { ValueSelector, Var, Variable } from '@/app/components/workflow/typ
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
import { checkKeys, replaceSpaceWithUnderscreInVarNameInput } from '@/utils/var' import { checkKeys, replaceSpaceWithUnderscreInVarNameInput } from '@/utils/var'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
import { ReactSortable } from 'react-sortablejs'
import { v4 as uuid4 } from 'uuid'
import { RiDraggable } from '@remixicon/react'
import cn from '@/utils/classnames'
type Props = { type Props = {
nodeId: string nodeId: string
@@ -36,6 +40,14 @@ const VarList: FC<Props> = ({
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const listWithIds = useMemo(() => list.map((item) => {
const id = uuid4()
return {
id,
variable: { ...item },
}
}), [list])
const handleVarNameChange = useCallback((index: number) => { const handleVarNameChange = useCallback((index: number) => {
return (e: React.ChangeEvent<HTMLInputElement>) => { return (e: React.ChangeEvent<HTMLInputElement>) => {
replaceSpaceWithUnderscreInVarNameInput(e.target) replaceSpaceWithUnderscreInVarNameInput(e.target)
@@ -105,36 +117,56 @@ const VarList: FC<Props> = ({
} }
}, [list, onChange]) }, [list, onChange])
const varCount = list.length
return ( return (
<div className='space-y-2'> <ReactSortable
{list.map((item, index) => ( className='space-y-2'
<div className='flex items-center space-x-1' key={index}> list={listWithIds}
<Input setList={(list) => { onChange(list.map(item => item.variable)) }}
wrapperClassName='w-[120px]' handle='.handle'
disabled={readonly} ghostClass='opacity-50'
value={list[index].variable} animation={150}
onChange={handleVarNameChange(index)} >
placeholder={t('workflow.common.variableNamePlaceholder')!} {list.map((variable, index) => {
/> const canDrag = (() => {
<VarReferencePicker if (readonly)
nodeId={nodeId} return false
readonly={readonly} return varCount > 1
isShowNodeName })()
className='grow' return (
value={item.variable_type === VarKindType.constant ? (item.value || '') : (item.value_selector || [])} <div className={cn('flex items-center space-x-1', 'group relative')} key={index}>
isSupportConstantValue={isSupportConstantValue} <Input
onChange={handleVarReferenceChange(index)} wrapperClassName='w-[120px]'
defaultVarKindType={item.variable_type} disabled={readonly}
onlyLeafNodeVar={onlyLeafNodeVar} value={variable.variable}
filterVar={filterVar} onChange={handleVarNameChange(index)}
isSupportFileVar={isSupportFileVar} placeholder={t('workflow.common.variableNamePlaceholder')!}
/> />
{!readonly && ( <VarReferencePicker
<RemoveButton onClick={handleVarRemove(index)}/> nodeId={nodeId}
)} readonly={readonly}
</div> isShowNodeName
))} className='grow'
</div> value={variable.variable_type === VarKindType.constant ? (variable.value || '') : (variable.value_selector || [])}
isSupportConstantValue={isSupportConstantValue}
onChange={handleVarReferenceChange(index)}
defaultVarKindType={variable.variable_type}
onlyLeafNodeVar={onlyLeafNodeVar}
filterVar={filterVar}
isSupportFileVar={isSupportFileVar}
/>
{!readonly && (
<RemoveButton onClick={handleVarRemove(index)}/>
)}
{canDrag && <RiDraggable className={cn(
'handle absolute -left-4 top-2.5 hidden h-3 w-3 cursor-pointer text-text-quaternary',
'group-hover:block',
)} />}
</div>
)
})}
</ReactSortable>
) )
} }
export default React.memo(VarList) export default React.memo(VarList)