Add comprehensive file information display to file manager

Backend improvements:
- Enhanced ls -la parsing to extract complete file metadata (size, permissions, owner, group, modified date)
- Added support for symbolic link target detection
- Changed API response format to include both files array and current path
- Improved file path construction logic

Frontend improvements:
- Updated global FileItem interface with all file metadata fields
- Removed duplicate local FileItem definitions across components
- Added formatFileSize utility with proper 0-byte handling ("0 B" instead of "-")
- Fixed 0-byte file display logic (changed from falsy check to explicit null/undefined check)
- Implemented file size display in both grid and list views
- Added smart filename collision handling with auto-incrementing suffixes
- Enhanced create-then-edit workflow to preserve items even when canceled
- Improved inline editing input styling to match shadcn design system
- Optimized input field dimensions (width constraints: 60-120px grid, max 200px list)

File creation improvements:
- Removed spaces from default names to avoid path issues (NewFile.txt, NewFolder)
- Added intelligent unique name generation (NewFile.txt → NewFile1.txt → NewFile2.txt)
- Changed cancel behavior to create items with default names instead of discarding
- Fixed SSH connection reliability with auto-reconnection for all operations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ZacharyZcR
2025-09-16 19:12:49 +08:00
parent fb7b452a1c
commit 16de73d6ad
4 changed files with 130 additions and 65 deletions

View File

@@ -311,20 +311,50 @@ app.get("/ssh/file_manager/ssh/listFiles", (req, res) => {
const parts = line.split(/\s+/);
if (parts.length >= 9) {
const permissions = parts[0];
const name = parts.slice(8).join(" ");
const linkCount = parts[1];
const owner = parts[2];
const group = parts[3];
const size = parseInt(parts[4], 10);
// 日期可能占夨3个部分月 日 时间)或者是(月 日 年)
let dateStr = "";
let nameStartIndex = 8;
if (parts[5] && parts[6] && parts[7]) {
// 常规格式: 月 日 时间/年
dateStr = `${parts[5]} ${parts[6]} ${parts[7]}`;
}
const name = parts.slice(nameStartIndex).join(" ");
const isDirectory = permissions.startsWith("d");
const isLink = permissions.startsWith("l");
if (name === "." || name === "..") continue;
// 解析符号链接目标
let actualName = name;
let linkTarget = undefined;
if (isLink && name.includes(" -> ")) {
const linkParts = name.split(" -> ");
actualName = linkParts[0];
linkTarget = linkParts[1];
}
files.push({
name,
name: actualName,
type: isDirectory ? "directory" : isLink ? "link" : "file",
size: isDirectory ? undefined : size, // 目录不显示大小
modified: dateStr,
permissions,
owner,
group,
linkTarget, // 符号链接的目标
path: `${sshPath.endsWith('/') ? sshPath : sshPath + '/'}${actualName}` // 添加完整路径
});
}
}
res.json(files);
res.json({ files, path: sshPath });
});
});
});