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.
87 lines
2.3 KiB
TypeScript
87 lines
2.3 KiB
TypeScript
import { useState, useCallback } from 'react';
|
|
|
|
interface FileItem {
|
|
name: string;
|
|
type: "file" | "directory" | "link";
|
|
path: string;
|
|
size?: number;
|
|
modified?: string;
|
|
permissions?: string;
|
|
owner?: string;
|
|
group?: string;
|
|
}
|
|
|
|
export function useFileSelection() {
|
|
const [selectedFiles, setSelectedFiles] = useState<FileItem[]>([]);
|
|
|
|
const selectFile = useCallback((file: FileItem, multiSelect = false) => {
|
|
if (multiSelect) {
|
|
setSelectedFiles(prev => {
|
|
const isSelected = prev.some(f => f.path === file.path);
|
|
if (isSelected) {
|
|
return prev.filter(f => f.path !== file.path);
|
|
} else {
|
|
return [...prev, file];
|
|
}
|
|
});
|
|
} else {
|
|
setSelectedFiles([file]);
|
|
}
|
|
}, []);
|
|
|
|
const selectRange = useCallback((files: FileItem[], startFile: FileItem, endFile: FileItem) => {
|
|
const startIndex = files.findIndex(f => f.path === startFile.path);
|
|
const endIndex = files.findIndex(f => f.path === endFile.path);
|
|
|
|
if (startIndex !== -1 && endIndex !== -1) {
|
|
const start = Math.min(startIndex, endIndex);
|
|
const end = Math.max(startIndex, endIndex);
|
|
const rangeFiles = files.slice(start, end + 1);
|
|
setSelectedFiles(rangeFiles);
|
|
}
|
|
}, []);
|
|
|
|
const selectAll = useCallback((files: FileItem[]) => {
|
|
setSelectedFiles([...files]);
|
|
}, []);
|
|
|
|
const clearSelection = useCallback(() => {
|
|
setSelectedFiles([]);
|
|
}, []);
|
|
|
|
const toggleSelection = useCallback((file: FileItem) => {
|
|
setSelectedFiles(prev => {
|
|
const isSelected = prev.some(f => f.path === file.path);
|
|
if (isSelected) {
|
|
return prev.filter(f => f.path !== file.path);
|
|
} else {
|
|
return [...prev, file];
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
const isSelected = useCallback((file: FileItem) => {
|
|
return selectedFiles.some(f => f.path === file.path);
|
|
}, [selectedFiles]);
|
|
|
|
const getSelectedCount = useCallback(() => {
|
|
return selectedFiles.length;
|
|
}, [selectedFiles]);
|
|
|
|
const setSelection = useCallback((files: FileItem[]) => {
|
|
console.log('Setting selection to:', files.map(f => f.name));
|
|
setSelectedFiles(files);
|
|
}, []);
|
|
|
|
return {
|
|
selectedFiles,
|
|
selectFile,
|
|
selectRange,
|
|
selectAll,
|
|
clearSelection,
|
|
toggleSelection,
|
|
isSelected,
|
|
getSelectedCount,
|
|
setSelection
|
|
};
|
|
} |