Clean up frontend files and read me translations

This commit is contained in:
LukeGus
2025-09-12 00:57:08 -05:00
parent 4fdda82a30
commit ad05021fc5
63 changed files with 1478 additions and 1622 deletions

View File

@@ -1,8 +1,8 @@
import React from "react";
import { FileManagerTabList } from "./FileManagerTabList.tsx";
import {FileManagerTabList} from "./FileManagerTabList.tsx";
interface FileManagerTopNavbarProps {
tabs: {id: string | number, title: string}[];
tabs: { id: string | number, title: string }[];
activeTab: string | number;
setActiveTab: (tab: string | number) => void;
closeTab: (tab: string | number) => void;
@@ -10,8 +10,8 @@ interface FileManagerTopNavbarProps {
}
export function FIleManagerTopNavbar(props: FileManagerTopNavbarProps): React.ReactElement {
const { tabs, activeTab, setActiveTab, closeTab, onHomeClick } = props;
const {tabs, activeTab, setActiveTab, closeTab, onHomeClick} = props;
return (
<FileManagerTabList
tabs={tabs}

View File

@@ -1,6 +1,5 @@
import React, {useState, useEffect, useRef} from "react";
import {FileManagerLeftSidebar} from "@/ui/Desktop/Apps/File Manager/FileManagerLeftSidebar.tsx";
import {FileManagerTabList} from "@/ui/Desktop/Apps/File Manager/FileManagerTabList.tsx";
import {FileManagerHomeView} from "@/ui/Desktop/Apps/File Manager/FileManagerHomeView.tsx";
import {FileManagerFileEditor} from "@/ui/Desktop/Apps/File Manager/FileManagerFileEditor.tsx";
import {FileManagerOperations} from "@/ui/Desktop/Apps/File Manager/FileManagerOperations.tsx";
@@ -8,7 +7,6 @@ import {Button} from '@/components/ui/button.tsx';
import {FIleManagerTopNavbar} from "@/ui/Desktop/Apps/File Manager/FIleManagerTopNavbar.tsx";
import {cn} from '@/lib/utils.ts';
import {Save, RefreshCw, Settings, Trash2} from 'lucide-react';
import {Separator} from '@/components/ui/separator.tsx';
import {toast} from 'sonner';
import {useTranslation} from 'react-i18next';
import {
@@ -26,9 +24,9 @@ import {
getSSHStatus,
connectSSH
} from '@/ui/main-axios.ts';
import type { SSHHost, Tab, FileManagerProps } from '../../../types/index.js';
import type {SSHHost, Tab} from '../../../types/index.js';
export function FileManager({onSelectView, embedded = false, initialHost = null, onClose}: {
export function FileManager({onSelectView, initialHost = null, onClose}: {
onSelectView?: (view: string) => void,
embedded?: boolean,
initialHost?: SSHHost | null,
@@ -122,10 +120,9 @@ export function FileManager({onSelectView, embedded = false, initialHost = null,
type: 'directory'
})));
} catch (err: any) {
console.error('Failed to fetch home data:', err);
const {toast} = await import('sonner');
toast.error(t('fileManager.failedToFetchHomeData'));
// Close the file manager tab on connection failure
if (onClose) {
onClose();
}
@@ -371,7 +368,6 @@ export function FileManager({onSelectView, embedded = false, initialHost = null,
loading: false
} : t));
// Handle toast notification from backend
if (result?.toast) {
toast[result.toast.type](result.toast.message);
} else {
@@ -389,7 +385,6 @@ export function FileManager({onSelectView, embedded = false, initialHost = null,
hostId: currentHost.id
});
} catch (recentErr) {
console.error('Failed to add recent file:', recentErr);
}
})(),
]).then(() => {
@@ -443,14 +438,13 @@ export function FileManager({onSelectView, embedded = false, initialHost = null,
try {
const {deleteSSHItem} = await import('@/ui/main-axios.ts');
const response = await deleteSSHItem(currentHost.id.toString(), item.path, item.type === 'directory');
// Handle toast notification from backend
if (response?.toast) {
toast[response.toast.type](response.toast.message);
} else {
toast.success(`${item.type === 'directory' ? t('fileManager.folder') : t('fileManager.file')} ${t('fileManager.deletedSuccessfully')}`);
}
setDeletingItem(null);
handleOperationComplete();
} catch (error: any) {
@@ -475,7 +469,8 @@ export function FileManager({onSelectView, embedded = false, initialHost = null,
onPathChange={updateCurrentPath}
/>
</div>
<div className="absolute top-0 left-64 right-0 bottom-0 flex items-center justify-center bg-dark-bg-darkest">
<div
className="absolute top-0 left-64 right-0 bottom-0 flex items-center justify-center bg-dark-bg-darkest">
<div className="text-center">
<h2 className="text-xl font-semibold text-white mb-2">{t('fileManager.connectToServer')}</h2>
<p className="text-muted-foreground">{t('fileManager.selectServerToEdit')}</p>
@@ -546,7 +541,8 @@ export function FileManager({onSelectView, embedded = false, initialHost = null,
</div>
</div>
</div>
<div className="absolute top-[44px] left-64 right-0 bottom-0 overflow-hidden z-[10] bg-dark-bg-very-light flex flex-col">
<div
className="absolute top-[44px] left-64 right-0 bottom-0 overflow-hidden z-[10] bg-dark-bg-very-light flex flex-col">
<div className="flex h-full">
<div className="flex-1">
{activeTab === 'home' ? (
@@ -605,7 +601,7 @@ export function FileManager({onSelectView, embedded = false, initialHost = null,
{t('fileManager.confirmDelete')}
</h3>
<p className="text-white mb-4">
{t('fileManager.confirmDeleteMessage', { name: deletingItem.name })}
{t('fileManager.confirmDeleteMessage', {name: deletingItem.name})}
{deletingItem.type === 'directory' && ` ${t('fileManager.deleteDirectoryWarning')}`}
</p>
<p className="text-red-400 text-sm mb-6">

View File

@@ -1,4 +1,4 @@
import React, {useState, useEffect} from "react";
import React, {useEffect} from "react";
import CodeMirror from "@uiw/react-codemirror";
import {loadLanguage} from '@uiw/codemirror-extensions-langs';
import {hyperLink} from '@uiw/codemirror-extensions-hyper-link';

View File

@@ -5,7 +5,7 @@ import {Tabs, TabsList, TabsTrigger, TabsContent} from '@/components/ui/tabs.tsx
import {Input} from '@/components/ui/input.tsx';
import {useState} from 'react';
import {useTranslation} from 'react-i18next';
import type { FileItem, ShortcutItem } from '../../../types/index';
import type {FileItem, ShortcutItem} from '../../../types/index';
interface FileManagerHomeViewProps {
recent: FileItem[];
@@ -111,9 +111,12 @@ export function FileManagerHomeView({
<div className="p-4 flex flex-col gap-4 h-full bg-dark-bg-darkest">
<Tabs value={tab} onValueChange={v => setTab(v as 'recent' | 'pinned' | 'shortcuts')} className="w-full">
<TabsList className="mb-4 bg-dark-bg border-2 border-dark-border">
<TabsTrigger value="recent" className="data-[state=active]:bg-dark-bg-button">{t('fileManager.recent')}</TabsTrigger>
<TabsTrigger value="pinned" className="data-[state=active]:bg-dark-bg-button">{t('fileManager.pinned')}</TabsTrigger>
<TabsTrigger value="shortcuts" className="data-[state=active]:bg-dark-bg-button">{t('fileManager.folderShortcuts')}</TabsTrigger>
<TabsTrigger value="recent"
className="data-[state=active]:bg-dark-bg-button">{t('fileManager.recent')}</TabsTrigger>
<TabsTrigger value="pinned"
className="data-[state=active]:bg-dark-bg-button">{t('fileManager.pinned')}</TabsTrigger>
<TabsTrigger value="shortcuts"
className="data-[state=active]:bg-dark-bg-button">{t('fileManager.folderShortcuts')}</TabsTrigger>
</TabsList>
<TabsContent value="recent" className="mt-0">

View File

@@ -1,6 +1,5 @@
import React, {useEffect, useState, useRef, forwardRef, useImperativeHandle} from 'react';
import {Separator} from '@/components/ui/separator.tsx';
import {CornerDownLeft, Folder, File, Server, ArrowUp, Pin, MoreVertical, Trash2, Edit3} from 'lucide-react';
import {Folder, File, ArrowUp, Pin, MoreVertical, Trash2, Edit3} from 'lucide-react';
import {ScrollArea} from '@/components/ui/scroll-area.tsx';
import {cn} from '@/lib/utils.ts';
import {Input} from '@/components/ui/input.tsx';
@@ -11,18 +10,16 @@ import {
listSSHFiles,
renameSSHItem,
deleteSSHItem,
getFileManagerRecent,
getFileManagerPinned,
addFileManagerPinned,
removeFileManagerPinned,
readSSHFile,
getSSHStatus,
connectSSH
} from '@/ui/main-axios.ts';
import type { SSHHost, FileManagerLeftSidebarProps } from '../../../types/index.js';
import type {SSHHost} from '../../../types/index.js';
const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
{onSelectView, onOpenFile, tabs, host, onOperationComplete, onError, onSuccess, onPathChange, onDeleteItem}: {
{onOpenFile, tabs, host, onOperationComplete, onPathChange, onDeleteItem}: {
onSelectView?: (view: string) => void;
onOpenFile: (file: any) => void;
tabs: any[];
@@ -55,7 +52,6 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
const [sshSessionId, setSshSessionId] = useState<string | null>(null);
const [filesLoading, setFilesLoading] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [connectingSSH, setConnectingSSH] = useState(false);
const [connectionCache, setConnectionCache] = useState<Record<string, {
sessionId: string;
@@ -287,7 +283,7 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
if (y < 0) {
y = 0;
}
setContextMenu({
visible: true,
x,
@@ -297,7 +293,7 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
};
const closeContextMenu = () => {
setContextMenu({ visible: false, x: 0, y: 0, item: null });
setContextMenu({visible: false, x: 0, y: 0, item: null});
};
const handleRename = async (item: any, newName: string) => {
@@ -320,24 +316,8 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
}
};
const handleDelete = async (item: any) => {
if (!sshSessionId) return;
try {
await deleteSSHItem(sshSessionId, item.path, item.type === 'directory');
toast.success(`${item.type === 'directory' ? t('common.folder') : t('common.file')} ${t('common.deletedSuccessfully')}`);
if (onOperationComplete) {
onOperationComplete();
} else {
fetchFiles();
}
} catch (error: any) {
toast.error(error?.response?.data?.error || t('fileManager.failedToDeleteItem'));
}
};
const startRename = (item: any) => {
setRenamingItem({ item, newName: item.name });
setRenamingItem({item, newName: item.name});
closeContextMenu();
};
@@ -360,10 +340,12 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
return (
<div className="flex flex-col h-full w-[256px] max-w-[256px]">
<div className="flex flex-col flex-grow min-h-0">
<div className="flex-1 w-full h-full flex flex-col bg-dark-bg-darkest border-r-2 border-dark-border overflow-hidden p-0 relative min-h-0">
<div
className="flex-1 w-full h-full flex flex-col bg-dark-bg-darkest border-r-2 border-dark-border overflow-hidden p-0 relative min-h-0">
{host && (
<div className="flex flex-col h-full w-full max-w-[260px]">
<div className="flex items-center gap-2 px-2 py-1.5 border-b-2 border-dark-border bg-dark-bg z-20 max-w-[260px]">
<div
className="flex items-center gap-2 px-2 py-1.5 border-b-2 border-dark-border bg-dark-bg z-20 max-w-[260px]">
<Button
size="icon"
variant="outline"
@@ -405,14 +387,15 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
{connectingSSH || filesLoading ? (
<div className="text-xs text-muted-foreground">{t('common.loading')}</div>
) : filteredFiles.length === 0 ? (
<div className="text-xs text-muted-foreground">{t('fileManager.noFilesOrFoldersFound')}</div>
<div
className="text-xs text-muted-foreground">{t('fileManager.noFilesOrFoldersFound')}</div>
) : (
<div className="flex flex-col gap-1">
{filteredFiles.map((item: any) => {
const isOpen = (tabs || []).some((t: any) => t.id === item.path);
const isRenaming = renamingItem?.item?.path === item.path;
const isDeleting = false;
return (
<div
key={item.path}
@@ -425,18 +408,23 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
{isRenaming ? (
<div className="flex items-center gap-2 flex-1 min-w-0">
{item.type === 'directory' ?
<Folder className="w-4 h-4 text-blue-400 flex-shrink-0"/> :
<File className="w-4 h-4 text-muted-foreground flex-shrink-0"/>}
<Folder
className="w-4 h-4 text-blue-400 flex-shrink-0"/> :
<File
className="w-4 h-4 text-muted-foreground flex-shrink-0"/>}
<Input
value={renamingItem.newName}
onChange={(e) => setRenamingItem(prev => prev ? {...prev, newName: e.target.value} : null)}
onChange={(e) => setRenamingItem(prev => prev ? {
...prev,
newName: e.target.value
} : null)}
className="flex-1 h-6 text-sm bg-dark-bg-button border border-dark-border-hover text-white"
autoFocus
onKeyDown={(e) => {
if (e.key === 'Enter') {
handleRename(item, renamingItem.newName);
} else if (e.key === 'Escape') {
setRenamingItem(null);
setRenamingItem(null);
}
}}
onBlur={() => handleRename(item, renamingItem.newName)}
@@ -454,13 +442,17 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
}))}
>
{item.type === 'directory' ?
<Folder className="w-4 h-4 text-blue-400 flex-shrink-0"/> :
<File className="w-4 h-4 text-muted-foreground flex-shrink-0"/>}
<span className="text-sm text-white truncate flex-1 min-w-0">{item.name}</span>
<Folder
className="w-4 h-4 text-blue-400 flex-shrink-0"/> :
<File
className="w-4 h-4 text-muted-foreground flex-shrink-0"/>}
<span
className="text-sm text-white truncate flex-1 min-w-0">{item.name}</span>
</div>
<div className="flex items-center gap-1">
{item.type === 'file' && (
<Button size="icon" variant="ghost" className="h-7 w-7"
<Button size="icon" variant="ghost"
className="h-7 w-7"
disabled={isOpen}
onClick={async (e) => {
e.stopPropagation();
@@ -474,7 +466,10 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
sshSessionId: host?.id.toString()
});
setFiles(files.map(f =>
f.path === item.path ? { ...f, isPinned: false } : f
f.path === item.path ? {
...f,
isPinned: false
} : f
));
} else {
await addFileManagerPinned({
@@ -485,14 +480,18 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
sshSessionId: host?.id.toString()
});
setFiles(files.map(f =>
f.path === item.path ? { ...f, isPinned: true } : f
f.path === item.path ? {
...f,
isPinned: true
} : f
));
}
} catch (err) {
}
}}
>
<Pin className={`w-1 h-1 ${item.isPinned ? 'text-yellow-400 fill-current' : 'text-muted-foreground'}`}/>
<Pin
className={`w-1 h-1 ${item.isPinned ? 'text-yellow-400 fill-current' : 'text-muted-foreground'}`}/>
</Button>
)}
{!isOpen && (
@@ -505,7 +504,7 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
handleContextMenu(e, item);
}}
>
<MoreVertical className="w-4 h-4" />
<MoreVertical className="w-4 h-4"/>
</Button>
)}
</div>
@@ -536,14 +535,14 @@ const FileManagerLeftSidebar = forwardRef(function FileManagerSidebar(
className="w-full px-3 py-2 text-left text-sm text-white hover:bg-dark-hover flex items-center gap-2"
onClick={() => startRename(contextMenu.item)}
>
<Edit3 className="w-4 h-4" />
<Edit3 className="w-4 h-4"/>
Rename
</button>
<button
className="w-full px-3 py-2 text-left text-sm text-red-400 hover:bg-dark-hover flex items-center gap-2"
onClick={() => startDelete(contextMenu.item)}
>
<Trash2 className="w-4 h-4" />
<Trash2 className="w-4 h-4"/>
Delete
</button>
</div>

View File

@@ -1,8 +1,7 @@
import React from 'react';
import {Button} from '@/components/ui/button.tsx';
import {Card} from '@/components/ui/card.tsx';
import {Separator} from '@/components/ui/separator.tsx';
import {Plus, Folder, File, Star, Trash2, Edit, Link2, Server, Pin} from 'lucide-react';
import {Folder, File, Trash2, Pin} from 'lucide-react';
import {useTranslation} from 'react-i18next';
interface SSHConnection {
@@ -43,12 +42,6 @@ interface FileManagerLeftSidebarVileViewerProps {
}
export function FileManagerLeftSidebarFileViewer({
sshConnections,
onAddSSH,
onConnectSSH,
onEditSSH,
onDeleteSSH,
onPinSSH,
currentPath,
files,
onOpenFile,
@@ -58,12 +51,9 @@ export function FileManagerLeftSidebarFileViewer({
isLoading,
error,
isSSHMode,
onSwitchToLocal,
onSwitchToSSH,
currentSSH,
}: FileManagerLeftSidebarVileViewerProps) {
const {t} = useTranslation();
return (
<div className="flex flex-col h-full">
<div className="flex-1 bg-dark-bg-darkest p-2 overflow-y-auto">

View File

@@ -10,14 +10,13 @@ import {
Trash2,
Edit3,
X,
Check,
AlertCircle,
FileText,
Folder
} from 'lucide-react';
import {cn} from '@/lib/utils.ts';
import {useTranslation} from 'react-i18next';
import type { FileManagerOperationsProps } from '../../../types/index.js';
import type {FileManagerOperationsProps} from '../../../types/index.js';
export function FileManagerOperations({
currentPath,
@@ -56,7 +55,7 @@ export function FileManagerOperations({
};
checkContainerWidth();
const resizeObserver = new ResizeObserver(checkContainerWidth);
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
@@ -71,32 +70,28 @@ export function FileManagerOperations({
if (!uploadFile || !sshSessionId) return;
setIsLoading(true);
// Show loading toast
const {toast} = await import('sonner');
const loadingToast = toast.loading(t('fileManager.uploadingFile', { name: uploadFile.name }));
const loadingToast = toast.loading(t('fileManager.uploadingFile', {name: uploadFile.name}));
try {
const content = await uploadFile.text();
const {uploadSSHFile} = await import('@/ui/main-axios.ts');
const response = await uploadSSHFile(sshSessionId, currentPath, uploadFile.name, content);
// Dismiss loading toast and show success
toast.dismiss(loadingToast);
// Handle toast notification from backend
if (response?.toast) {
toast[response.toast.type](response.toast.message);
} else {
onSuccess(t('fileManager.fileUploadedSuccessfully', { name: uploadFile.name }));
onSuccess(t('fileManager.fileUploadedSuccessfully', {name: uploadFile.name}));
}
setShowUpload(false);
setUploadFile(null);
onOperationComplete();
} catch (error: any) {
// Dismiss loading toast and show error
toast.dismiss(loadingToast);
onError(error?.response?.data?.error || t('fileManager.failedToUploadFile'));
} finally {
@@ -108,31 +103,27 @@ export function FileManagerOperations({
if (!newFileName.trim() || !sshSessionId) return;
setIsLoading(true);
// Show loading toast
const {toast} = await import('sonner');
const loadingToast = toast.loading(t('fileManager.creatingFile', { name: newFileName.trim() }));
const loadingToast = toast.loading(t('fileManager.creatingFile', {name: newFileName.trim()}));
try {
const {createSSHFile} = await import('@/ui/main-axios.ts');
const response = await createSSHFile(sshSessionId, currentPath, newFileName.trim());
// Dismiss loading toast
toast.dismiss(loadingToast);
// Handle toast notification from backend
if (response?.toast) {
toast[response.toast.type](response.toast.message);
} else {
onSuccess(t('fileManager.fileCreatedSuccessfully', { name: newFileName.trim() }));
onSuccess(t('fileManager.fileCreatedSuccessfully', {name: newFileName.trim()}));
}
setShowCreateFile(false);
setNewFileName('');
onOperationComplete();
} catch (error: any) {
// Dismiss loading toast and show error
toast.dismiss(loadingToast);
onError(error?.response?.data?.error || t('fileManager.failedToCreateFile'));
} finally {
@@ -144,31 +135,27 @@ export function FileManagerOperations({
if (!newFolderName.trim() || !sshSessionId) return;
setIsLoading(true);
// Show loading toast
const {toast} = await import('sonner');
const loadingToast = toast.loading(t('fileManager.creatingFolder', { name: newFolderName.trim() }));
const loadingToast = toast.loading(t('fileManager.creatingFolder', {name: newFolderName.trim()}));
try {
const {createSSHFolder} = await import('@/ui/main-axios.ts');
const response = await createSSHFolder(sshSessionId, currentPath, newFolderName.trim());
// Dismiss loading toast
toast.dismiss(loadingToast);
// Handle toast notification from backend
if (response?.toast) {
toast[response.toast.type](response.toast.message);
} else {
onSuccess(t('fileManager.folderCreatedSuccessfully', { name: newFolderName.trim() }));
onSuccess(t('fileManager.folderCreatedSuccessfully', {name: newFolderName.trim()}));
}
setShowCreateFolder(false);
setNewFolderName('');
onOperationComplete();
} catch (error: any) {
// Dismiss loading toast and show error
toast.dismiss(loadingToast);
onError(error?.response?.data?.error || t('fileManager.failedToCreateFolder'));
} finally {
@@ -180,35 +167,31 @@ export function FileManagerOperations({
if (!deletePath || !sshSessionId) return;
setIsLoading(true);
// Show loading toast
const {toast} = await import('sonner');
const loadingToast = toast.loading(t('fileManager.deletingItem', {
const loadingToast = toast.loading(t('fileManager.deletingItem', {
type: deleteIsDirectory ? t('fileManager.folder') : t('fileManager.file'),
name: deletePath.split('/').pop()
}));
try {
const {deleteSSHItem} = await import('@/ui/main-axios.ts');
const response = await deleteSSHItem(sshSessionId, deletePath, deleteIsDirectory);
// Dismiss loading toast
toast.dismiss(loadingToast);
// Handle toast notification from backend
if (response?.toast) {
toast[response.toast.type](response.toast.message);
} else {
onSuccess(t('fileManager.itemDeletedSuccessfully', { type: deleteIsDirectory ? t('fileManager.folder') : t('fileManager.file') }));
onSuccess(t('fileManager.itemDeletedSuccessfully', {type: deleteIsDirectory ? t('fileManager.folder') : t('fileManager.file')}));
}
setShowDelete(false);
setDeletePath('');
setDeleteIsDirectory(false);
onOperationComplete();
} catch (error: any) {
// Dismiss loading toast and show error
toast.dismiss(loadingToast);
onError(error?.response?.data?.error || t('fileManager.failedToDeleteItem'));
} finally {
@@ -220,37 +203,33 @@ export function FileManagerOperations({
if (!renamePath || !newName.trim() || !sshSessionId) return;
setIsLoading(true);
// Show loading toast
const {toast} = await import('sonner');
const loadingToast = toast.loading(t('fileManager.renamingItem', {
const loadingToast = toast.loading(t('fileManager.renamingItem', {
type: renameIsDirectory ? t('fileManager.folder') : t('fileManager.file'),
oldName: renamePath.split('/').pop(),
newName: newName.trim()
}));
try {
const {renameSSHItem} = await import('@/ui/main-axios.ts');
const response = await renameSSHItem(sshSessionId, renamePath, newName.trim());
// Dismiss loading toast
toast.dismiss(loadingToast);
// Handle toast notification from backend
if (response?.toast) {
toast[response.toast.type](response.toast.message);
} else {
onSuccess(t('fileManager.itemRenamedSuccessfully', { type: renameIsDirectory ? t('fileManager.folder') : t('fileManager.file') }));
onSuccess(t('fileManager.itemRenamedSuccessfully', {type: renameIsDirectory ? t('fileManager.folder') : t('fileManager.file')}));
}
setShowRename(false);
setRenamePath('');
setRenameIsDirectory(false);
setNewName('');
onOperationComplete();
} catch (error: any) {
// Dismiss loading toast and show error
toast.dismiss(loadingToast);
onError(error?.response?.data?.error || t('fileManager.failedToRenameItem'));
} finally {
@@ -577,7 +556,8 @@ export function FileManagerOperations({
<div className="bg-red-900/20 border border-red-500/30 rounded-lg p-3">
<div className="flex items-start gap-2 text-red-300">
<AlertCircle className="w-5 h-5 flex-shrink-0"/>
<span className="text-sm font-medium break-words">{t('fileManager.warningCannotUndo')}</span>
<span
className="text-sm font-medium break-words">{t('fileManager.warningCannotUndo')}</span>
</div>
</div>