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:
@@ -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(() => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user