diff --git a/src/ui/Desktop/Apps/File Manager/FileManagerSidebar.tsx b/src/ui/Desktop/Apps/File Manager/FileManagerSidebar.tsx index 1a1166e9..05d46d60 100644 --- a/src/ui/Desktop/Apps/File Manager/FileManagerSidebar.tsx +++ b/src/ui/Desktop/Apps/File Manager/FileManagerSidebar.tsx @@ -16,8 +16,12 @@ import { getRecentFiles, getPinnedFiles, getFolderShortcuts, - listSSHFiles + listSSHFiles, + removeRecentFile, + removePinnedFile, + removeFolderShortcut } from "@/ui/main-axios.ts"; +import { toast } from "sonner"; export interface SidebarItem { id: string; @@ -55,6 +59,19 @@ export function FileManagerSidebar({ const [directoryTree, setDirectoryTree] = useState([]); const [expandedFolders, setExpandedFolders] = useState>(new Set(['root'])); + // 右键菜单状态 + const [contextMenu, setContextMenu] = useState<{ + x: number; + y: number; + isVisible: boolean; + item: SidebarItem | null; + }>({ + x: 0, + y: 0, + isVisible: false, + item: null + }); + // 加载快捷功能数据 useEffect(() => { loadQuickAccessData(); @@ -110,6 +127,111 @@ export function FileManagerSidebar({ } }; + // 删除功能实现 + const handleRemoveRecentFile = async (item: SidebarItem) => { + if (!currentHost?.id) return; + + try { + await removeRecentFile(currentHost.id, item.path); + loadQuickAccessData(); // 重新加载数据 + toast.success(`已从最近访问中移除"${item.name}"`); + } catch (error) { + console.error('Failed to remove recent file:', error); + toast.error('移除失败'); + } + }; + + const handleUnpinFile = async (item: SidebarItem) => { + if (!currentHost?.id) return; + + try { + await removePinnedFile(currentHost.id, item.path); + loadQuickAccessData(); // 重新加载数据 + toast.success(`已取消固定"${item.name}"`); + } catch (error) { + console.error('Failed to unpin file:', error); + toast.error('取消固定失败'); + } + }; + + const handleRemoveShortcut = async (item: SidebarItem) => { + if (!currentHost?.id) return; + + try { + await removeFolderShortcut(currentHost.id, item.path); + loadQuickAccessData(); // 重新加载数据 + toast.success(`已移除快捷方式"${item.name}"`); + } catch (error) { + console.error('Failed to remove shortcut:', error); + toast.error('移除快捷方式失败'); + } + }; + + const handleClearAllRecent = async () => { + if (!currentHost?.id || recentItems.length === 0) return; + + try { + // 批量删除所有recent文件 + await Promise.all( + recentItems.map(item => removeRecentFile(currentHost.id, item.path)) + ); + loadQuickAccessData(); // 重新加载数据 + toast.success(`已清除所有最近访问记录`); + } catch (error) { + console.error('Failed to clear recent files:', error); + toast.error('清除失败'); + } + }; + + // 右键菜单处理 + const handleContextMenu = (e: React.MouseEvent, item: SidebarItem) => { + e.preventDefault(); + e.stopPropagation(); + + setContextMenu({ + x: e.clientX, + y: e.clientY, + isVisible: true, + item + }); + }; + + const closeContextMenu = () => { + setContextMenu(prev => ({ ...prev, isVisible: false, item: null })); + }; + + // 点击外部关闭菜单 + useEffect(() => { + if (!contextMenu.isVisible) return; + + const handleClickOutside = (event: MouseEvent) => { + const target = event.target as Element; + const menuElement = document.querySelector('[data-sidebar-context-menu]'); + + if (!menuElement?.contains(target)) { + closeContextMenu(); + } + }; + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + closeContextMenu(); + } + }; + + // 延迟添加监听器,避免立即触发 + const timeoutId = setTimeout(() => { + document.addEventListener('mousedown', handleClickOutside); + document.addEventListener('keydown', handleKeyDown); + }, 50); + + return () => { + clearTimeout(timeoutId); + document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('keydown', handleKeyDown); + }; + }, [contextMenu.isVisible]); + const loadDirectoryTree = async () => { if (!sshSessionId) return; @@ -238,6 +360,12 @@ export function FileManagerSidebar({ )} style={{ paddingLeft: `${8 + level * 16}px` }} onClick={() => handleItemClick(item)} + onContextMenu={(e) => { + // 只有快捷功能项才需要右键菜单 + if (item.type === 'recent' || item.type === 'pinned' || item.type === 'shortcut') { + handleContextMenu(e, item); + } + }} > {item.type === 'folder' && ( + {recentItems.length > 1 && ( + <> +
+ + + )} + + )} + + {contextMenu.item.type === 'pinned' && ( + + )} + + {contextMenu.item.type === 'shortcut' && ( + + )} +
+ + )} + ); } \ No newline at end of file