'use client' import type { NodeMenuType } from '../../constants' import * as React from 'react' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { FileAdd, FolderAdd } from '@/app/components/base/icons/src/vender/line/files' import { UploadCloud02 } from '@/app/components/base/icons/src/vender/line/general' import { Download02 } from '@/app/components/base/icons/src/vender/solid/general' import { ContextMenuSeparator, } from '@/app/components/base/ui/context-menu' import { DropdownMenuSeparator, } from '@/app/components/base/ui/dropdown-menu' import { useStore, useWorkflowStore } from '@/app/components/workflow/store' import { NODE_MENU_TYPE } from '../../constants' import MenuItem from './menu-item' const KBD_CUT = ['ctrl', 'x'] as const const KBD_PASTE = ['ctrl', 'v'] as const type NodeMenuProps = { type: NodeMenuType menuType: 'dropdown' | 'context' nodeId?: string actionNodeIds?: string[] onClose: () => void fileInputRef: React.RefObject folderInputRef: React.RefObject isLoading: boolean onDownload: () => void onNewFile: () => void onNewFolder: () => void onFileChange: React.ChangeEventHandler onFolderChange: React.ChangeEventHandler onRename: () => void onDeleteClick: () => void onImportSkills?: () => void } const NodeMenu = ({ type, menuType, nodeId, actionNodeIds, onClose, fileInputRef, folderInputRef, isLoading, onDownload, onNewFile, onNewFolder, onFileChange, onFolderChange, onRename, onDeleteClick, onImportSkills, }: NodeMenuProps) => { const { t } = useTranslation('workflow') const storeApi = useWorkflowStore() const hasClipboard = useStore(s => s.hasClipboard()) const isRoot = type === NODE_MENU_TYPE.ROOT const isFolder = type === NODE_MENU_TYPE.FOLDER || isRoot const currentNodeId = nodeId const handleCut = useCallback(() => { const ids = actionNodeIds && actionNodeIds.length > 0 ? actionNodeIds : (currentNodeId ? [currentNodeId] : []) if (ids.length > 0) { storeApi.getState().cutNodes(ids) onClose() } }, [actionNodeIds, currentNodeId, onClose, storeApi]) const handlePaste = useCallback(() => { window.dispatchEvent(new CustomEvent('skill:paste')) onClose() }, [onClose]) const handleCreateFile = useCallback(() => { storeApi.getState().setFileTreeSearchTerm('') onNewFile() }, [onNewFile, storeApi]) const handleCreateFolder = useCallback(() => { storeApi.getState().setFileTreeSearchTerm('') onNewFolder() }, [onNewFolder, storeApi]) const showRenameDelete = isFolder ? !isRoot : true const Separator = menuType === 'dropdown' ? DropdownMenuSeparator : ContextMenuSeparator return ( <> {isFolder && ( <> fileInputRef.current?.click()} disabled={isLoading} /> folderInputRef.current?.click()} disabled={isLoading} /> {isRoot && ( <> onImportSkills?.()} disabled={isLoading} tooltip={t('skill.startTab.importSkillDesc')} /> )} {(showRenameDelete || hasClipboard) && } )} {!isFolder && ( <> )} {!isRoot && ( <> )} {isFolder && hasClipboard && ( )} {showRenameDelete && ( <> )} ) } export default React.memo(NodeMenu)