fix(skill): address code review issues for tab management

1. Add confirmation dialog when closing dirty tabs
2. Fix file double-click race condition with useDelayedClick hook
3. Fix previewTabId orphan state in closeTab
4. Remove auto-pin on every keystroke (VS Code behavior)
5. Extract shared MenuItem component to eliminate duplication
6. Make nodeId optional when node is provided (reduce props drilling)
This commit is contained in:
yyh
2026-01-16 11:17:19 +08:00
parent 17990512ce
commit f1ce933b33
11 changed files with 174 additions and 92 deletions

View File

@ -0,0 +1,40 @@
import { useCallback, useRef } from 'react'
type UseDelayedClickOptions = {
delay?: number
onSingleClick: () => void
onDoubleClick: () => void
}
/**
* Hook to distinguish between single-click and double-click events.
* Single-click is delayed to allow double-click detection.
* Double-click cancels any pending single-click.
*/
export function useDelayedClick({
delay = 200,
onSingleClick,
onDoubleClick,
}: UseDelayedClickOptions) {
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
const handleClick = useCallback(() => {
if (timeoutRef.current)
clearTimeout(timeoutRef.current)
timeoutRef.current = setTimeout(() => {
onSingleClick()
timeoutRef.current = null
}, delay)
}, [delay, onSingleClick])
const handleDoubleClick = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
timeoutRef.current = null
}
onDoubleClick()
}, [onDoubleClick])
return { handleClick, handleDoubleClick }
}

View File

@ -16,18 +16,19 @@ import { getAllDescendantFileIds } from '../utils/tree-utils'
import { useSkillAssetTreeData } from './use-skill-asset-tree'
type UseFileOperationsOptions = {
nodeId: string
nodeId?: string
onClose: () => void
treeRef?: React.RefObject<TreeApi<TreeNodeData> | null>
node?: NodeApi<TreeNodeData>
}
export function useFileOperations({
nodeId,
nodeId: explicitNodeId,
onClose,
treeRef,
node,
}: UseFileOperationsOptions) {
const nodeId = node?.data.id ?? explicitNodeId ?? ''
const { t } = useTranslation('workflow')
const fileInputRef = useRef<HTMLInputElement>(null)
const folderInputRef = useRef<HTMLInputElement>(null)