Fix critical file selection and SSH connection issues in modern file manager

Major fixes that make the modern file manager fully functional:

🔧 Core Issues Fixed:
- File selection bug: All files showing as selected when only one was clicked
- SSH connection not established: 400 errors when loading directories
- File path undefined: Backend data missing proper path construction

🎯 File Selection Fix:
- Root cause: All file.path values were 'undefined', causing path comparison
  to always return true ('undefined' === 'undefined')
- Solution: Manually construct file paths from currentPath + fileName
- Result: Proper single/multi/range selection now works correctly

🔗 SSH Connection Enhancement:
- Added comprehensive connection status checking before operations
- Implemented automatic reconnection on connection failures
- Enhanced error handling with detailed logging and user feedback
- Added connection parameter validation and debugging

🛠️ Technical Improvements:
- Enhanced useFileSelection hook with safer state management
- Added extensive debugging logs for file operations and path construction
- Improved error messages and user feedback across all operations
- Robust file path building matching traditional file manager logic

The modern file manager now provides a fully functional, desktop-class
file management experience with proper selection, navigation, and operations.
This commit is contained in:
ZacharyZcR
2025-09-16 16:21:06 +08:00
parent b50ee1965f
commit cd70e63a1b
3 changed files with 94 additions and 11 deletions

View File

@@ -27,7 +27,8 @@ import {
createSSHFolder,
deleteSSHItem,
renameSSHItem,
connectSSH
connectSSH,
getSSHStatus
} from "@/ui/main-axios.ts";
interface FileItem {
@@ -83,7 +84,7 @@ export function FileManagerModern({ initialHost, onClose }: FileManagerModernPro
selectFile,
selectAll,
clearSelection,
setSelectedFiles
setSelection
} = useFileSelection();
const { isDragging, dragHandlers } = useDragAndDrop({
@@ -111,11 +112,24 @@ export function FileManagerModern({ initialHost, onClose }: FileManagerModernPro
try {
setIsLoading(true);
console.log("Initializing SSH connection for host:", currentHost.name, "ID:", currentHost.id);
// 使用主机ID作为会话ID
const sessionId = currentHost.id.toString();
console.log("Using session ID:", sessionId);
// 调用connectSSH建立连接
await connectSSH(sessionId, {
console.log("Connecting to SSH with config:", {
hostId: currentHost.id,
ip: currentHost.ip,
port: currentHost.port,
username: currentHost.username,
authType: currentHost.authType,
credentialId: currentHost.credentialId,
userId: currentHost.userId
});
const result = await connectSSH(sessionId, {
hostId: currentHost.id,
ip: currentHost.ip,
port: currentHost.port,
@@ -128,26 +142,67 @@ export function FileManagerModern({ initialHost, onClose }: FileManagerModernPro
userId: currentHost.userId
});
console.log("SSH connection result:", result);
setSshSessionId(sessionId);
console.log("SSH session ID set to:", sessionId);
} catch (error: any) {
toast.error(t("fileManager.failedToConnect"));
console.error("SSH connection failed:", error);
toast.error(t("fileManager.failedToConnect") + ": " + (error.message || error));
} finally {
setIsLoading(false);
}
}
async function loadDirectory(path: string) {
if (!sshSessionId) return;
if (!sshSessionId) {
console.error("Cannot load directory: no SSH session ID");
return;
}
try {
setIsLoading(true);
console.log("Loading directory:", path, "with session ID:", sshSessionId);
// 首先检查SSH连接状态
try {
const status = await getSSHStatus(sshSessionId);
console.log("SSH connection status:", status);
if (!status.connected) {
console.log("SSH not connected, attempting to reconnect...");
await initializeSSHConnection();
return; // 重连后会触发useEffect重新加载目录
}
} catch (statusError) {
console.log("Failed to get SSH status, attempting to reconnect...");
await initializeSSHConnection();
return;
}
const contents = await listSSHFiles(sshSessionId, path);
setFiles(contents || []);
console.log("Directory contents loaded:", contents?.length || 0, "items");
console.log("Raw file data from backend:", contents);
// 为文件添加完整路径
const filesWithPath = (contents || []).map(file => ({
...file,
path: path + (path.endsWith("/") ? "" : "/") + file.name
}));
console.log("Files with constructed paths:", filesWithPath.map(f => ({ name: f.name, path: f.path })));
setFiles(filesWithPath);
clearSelection();
} catch (error: any) {
toast.error(t("fileManager.failedToLoadDirectory"));
console.error("Failed to load directory:", error);
// 如果是连接错误,尝试重连
if (error.message?.includes("connection") || error.message?.includes("established")) {
console.log("Connection error detected, attempting to reconnect...");
await initializeSSHConnection();
} else {
toast.error(t("fileManager.failedToLoadDirectory") + ": " + (error.message || error));
}
} finally {
setIsLoading(false);
}
@@ -440,9 +495,9 @@ export function FileManagerModern({ initialHost, onClose }: FileManagerModernPro
<FileManagerGrid
files={filteredFiles}
selectedFiles={selectedFiles}
onFileSelect={selectFile}
onFileSelect={() => {}} // 不再需要这个回调使用onSelectionChange
onFileOpen={handleFileOpen}
onSelectionChange={setSelectedFiles}
onSelectionChange={setSelection}
currentPath={currentPath}
isLoading={isLoading}
onPathChange={setCurrentPath}