mirror of
https://github.com/langgenius/dify.git
synced 2026-03-27 17:19:55 +08:00
100 lines
2.5 KiB
TypeScript
100 lines
2.5 KiB
TypeScript
'use client'
|
|
|
|
import type { NodeApi } from 'react-arborist'
|
|
import type { TreeNodeData } from '../../type'
|
|
import * as React from 'react'
|
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
type TreeEditInputProps = {
|
|
node: NodeApi<TreeNodeData>
|
|
}
|
|
|
|
const TreeEditInput = ({ node }: TreeEditInputProps) => {
|
|
const { t } = useTranslation('workflow')
|
|
const inputRef = useRef<HTMLInputElement>(null)
|
|
const isMountedRef = useRef(true)
|
|
const submitLockRef = useRef(false)
|
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
const isFolder = node.data.node_type === 'folder'
|
|
const placeholder = isFolder
|
|
? t('skillSidebar.folderNamePlaceholder')
|
|
: t('skillSidebar.fileNamePlaceholder')
|
|
|
|
useEffect(() => {
|
|
const input = inputRef.current
|
|
if (!input)
|
|
return
|
|
input.focus()
|
|
const name = input.value
|
|
const dotIndex = isFolder ? -1 : name.lastIndexOf('.')
|
|
if (dotIndex > 0)
|
|
input.setSelectionRange(0, dotIndex)
|
|
else
|
|
input.select()
|
|
}, [isFolder])
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
isMountedRef.current = false
|
|
}
|
|
}, [])
|
|
|
|
const handleSubmit = useCallback(async () => {
|
|
if (submitLockRef.current)
|
|
return
|
|
|
|
submitLockRef.current = true
|
|
setIsSubmitting(true)
|
|
|
|
try {
|
|
await node.tree.submit(node, inputRef.current?.value || '')
|
|
}
|
|
finally {
|
|
submitLockRef.current = false
|
|
if (isMountedRef.current)
|
|
setIsSubmitting(false)
|
|
}
|
|
}, [node])
|
|
|
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
e.stopPropagation()
|
|
if (e.key === 'Escape') {
|
|
if (submitLockRef.current)
|
|
return
|
|
node.reset()
|
|
}
|
|
else if (e.key === 'Enter') {
|
|
e.preventDefault()
|
|
void handleSubmit()
|
|
}
|
|
}
|
|
|
|
const handleBlur = () => {
|
|
if (submitLockRef.current)
|
|
return
|
|
node.reset()
|
|
}
|
|
|
|
const ariaLabel = isFolder
|
|
? t('skillSidebar.renameFolderInput')
|
|
: t('skillSidebar.renameFileInput')
|
|
|
|
return (
|
|
<input
|
|
ref={inputRef}
|
|
type="text"
|
|
defaultValue={node.data.name}
|
|
placeholder={placeholder}
|
|
aria-label={ariaLabel}
|
|
disabled={isSubmitting}
|
|
onKeyDown={handleKeyDown}
|
|
onBlur={handleBlur}
|
|
onClick={e => e.stopPropagation()}
|
|
className="min-w-0 flex-1 rounded border border-components-input-border-active bg-transparent px-1 text-[13px] font-normal leading-4 text-text-primary outline-none placeholder:text-text-placeholder"
|
|
/>
|
|
)
|
|
}
|
|
|
|
export default React.memo(TreeEditInput)
|