FIX: Automatically cleanup deleted files from recent/pinned lists

File Cleanup Implementation:
- Detect file-not-found errors when opening files from recent/pinned lists
- Automatically remove missing files from both recent and pinned file lists
- Refresh sidebar to reflect updated lists immediately after cleanup
- Prevent error dialogs from appearing when files are successfully cleaned up

Backend Improvements:
- Enhanced SSH file manager to return proper 404 status for missing files
- Added fileNotFound flag in error responses for better error detection
- Improved error categorization for file access failures

Frontend Error Handling:
- Added onFileNotFound callback prop to FileWindow component
- Implemented handleFileNotFound function in FileManagerModern
- Enhanced error detection logic to catch various "file not found" scenarios
- Better error messages with internationalization support

Translation Additions:
- fileNotFoundAndRemoved: Notify user when file is cleaned up
- failedToLoadFile: Generic file loading error message
- serverErrorOccurred: Server error fallback message
- Chinese translations for all new error messages

Technical Details:
- Uses existing removeRecentFile and removePinnedFile API calls
- Triggers sidebar refresh via setSidebarRefreshTrigger
- Maintains backward compatibility with existing error handling
- Preserves error logging for debugging purposes

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ZacharyZcR
2025-09-25 07:49:48 +08:00
parent c780ad2f18
commit fdd1218b03
5 changed files with 65 additions and 5 deletions

View File

@@ -43,6 +43,7 @@ import {
addRecentFile,
addPinnedFile,
removePinnedFile,
removeRecentFile,
addFolderShortcut,
getPinnedFiles,
} from "@/ui/main-axios.ts";
@@ -757,6 +758,7 @@ function FileManagerContent({ initialHost, onClose }: FileManagerModernProps) {
sshHost={currentHost}
initialX={offsetX}
initialY={offsetY}
onFileNotFound={handleFileNotFound}
/>
);
@@ -1553,6 +1555,26 @@ function FileManagerContent({ initialHost, onClose }: FileManagerModernProps) {
await handleFileOpen(file);
}
// Handle file not found - cleanup from recent and pinned lists
async function handleFileNotFound(file: FileItem) {
if (!currentHost) return;
try {
// Remove from recent files
await removeRecentFile(currentHost.id, file.path);
// Remove from pinned files
await removePinnedFile(currentHost.id, file.path);
// Trigger sidebar refresh to update the UI
setSidebarRefreshTrigger(prev => prev + 1);
console.log(`Cleaned up missing file from recent/pinned lists: ${file.path}`);
} catch (error) {
console.error("Failed to cleanup missing file:", error);
}
}
// Clear createIntent when path changes
useEffect(() => {

View File

@@ -10,6 +10,7 @@ import {
connectSSH,
} from "@/ui/main-axios";
import { toast } from "sonner";
import { useTranslation } from "react-i18next";
interface FileItem {
name: string;
@@ -43,6 +44,7 @@ interface FileWindowProps {
sshHost: SSHHost;
initialX?: number;
initialY?: number;
onFileNotFound?: (file: FileItem) => void; // Callback for when file is not found
// readOnly parameter removed, determined internally by FileViewer based on file type
}
@@ -53,6 +55,7 @@ export function FileWindow({
sshHost,
initialX = 100,
initialY = 100,
onFileNotFound,
}: FileWindowProps) {
const {
closeWindow,
@@ -62,6 +65,8 @@ export function FileWindow({
windows,
} = useWindowManager();
const { t } = useTranslation();
const [content, setContent] = useState<string>("");
const [isLoading, setIsLoading] = useState(false);
const [isEditable, setIsEditable] = useState(false);
@@ -192,9 +197,26 @@ export function FileWindow({
`SSH connection failed. Please check your connection to ${sshHost.name} (${sshHost.ip}:${sshHost.port})`,
);
} else {
toast.error(
`Failed to load file: ${error.message || errorData?.error || "Unknown error"}`,
);
// Check if file not found (common error messages from cat command)
const errorMessage = errorData?.error || error.message || "Unknown error";
const isFileNotFound =
errorData?.fileNotFound ||
error.response?.status === 404 ||
errorMessage.includes("No such file or directory") ||
errorMessage.includes("cannot access") ||
errorMessage.includes("not found");
if (isFileNotFound && onFileNotFound) {
// Notify parent component about the missing file for cleanup
onFileNotFound(file);
toast.error(t("fileManager.fileNotFoundAndRemoved", { name: file.name }));
} else {
toast.error(t("fileManager.failedToLoadFile", {
error: errorMessage.includes("Server error occurred") ?
t("fileManager.serverErrorOccurred") :
errorMessage
}));
}
}
} finally {
setIsLoading(false);