Clean up frontend files and read me translations
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user