import React, {useState, useRef, useEffect} from 'react'; import {Button} from '@/components/ui/button.tsx'; import {Input} from '@/components/ui/input.tsx'; import {Card} from '@/components/ui/card.tsx'; import {Separator} from '@/components/ui/separator.tsx'; import { Upload, FilePlus, FolderPlus, Trash2, Edit3, X, AlertCircle, FileText, Folder } from 'lucide-react'; import {cn} from '@/lib/utils.ts'; import {useTranslation} from 'react-i18next'; import type {FileManagerOperationsProps} from '../../../types/index.js'; export function FileManagerOperations({ currentPath, sshSessionId, onOperationComplete, onError, onSuccess }: FileManagerOperationsProps) { const {t} = useTranslation(); const [showUpload, setShowUpload] = useState(false); const [showCreateFile, setShowCreateFile] = useState(false); const [showCreateFolder, setShowCreateFolder] = useState(false); const [showDelete, setShowDelete] = useState(false); const [showRename, setShowRename] = useState(false); const [uploadFile, setUploadFile] = useState(null); const [newFileName, setNewFileName] = useState(''); const [newFolderName, setNewFolderName] = useState(''); const [deletePath, setDeletePath] = useState(''); const [deleteIsDirectory, setDeleteIsDirectory] = useState(false); const [renamePath, setRenamePath] = useState(''); const [renameIsDirectory, setRenameIsDirectory] = useState(false); const [newName, setNewName] = useState(''); const [isLoading, setIsLoading] = useState(false); const [showTextLabels, setShowTextLabels] = useState(true); const fileInputRef = useRef(null); const containerRef = useRef(null); useEffect(() => { const checkContainerWidth = () => { if (containerRef.current) { const width = containerRef.current.offsetWidth; setShowTextLabels(width > 240); } }; checkContainerWidth(); const resizeObserver = new ResizeObserver(checkContainerWidth); if (containerRef.current) { resizeObserver.observe(containerRef.current); } return () => { resizeObserver.disconnect(); }; }, []); const handleFileUpload = async () => { if (!uploadFile || !sshSessionId) return; setIsLoading(true); const {toast} = await import('sonner'); 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); toast.dismiss(loadingToast); if (response?.toast) { toast[response.toast.type](response.toast.message); } else { onSuccess(t('fileManager.fileUploadedSuccessfully', {name: uploadFile.name})); } setShowUpload(false); setUploadFile(null); onOperationComplete(); } catch (error: any) { toast.dismiss(loadingToast); onError(error?.response?.data?.error || t('fileManager.failedToUploadFile')); } finally { setIsLoading(false); } }; const handleCreateFile = async () => { if (!newFileName.trim() || !sshSessionId) return; setIsLoading(true); const {toast} = await import('sonner'); 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()); toast.dismiss(loadingToast); if (response?.toast) { toast[response.toast.type](response.toast.message); } else { onSuccess(t('fileManager.fileCreatedSuccessfully', {name: newFileName.trim()})); } setShowCreateFile(false); setNewFileName(''); onOperationComplete(); } catch (error: any) { toast.dismiss(loadingToast); onError(error?.response?.data?.error || t('fileManager.failedToCreateFile')); } finally { setIsLoading(false); } }; const handleCreateFolder = async () => { if (!newFolderName.trim() || !sshSessionId) return; setIsLoading(true); const {toast} = await import('sonner'); 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()); toast.dismiss(loadingToast); if (response?.toast) { toast[response.toast.type](response.toast.message); } else { onSuccess(t('fileManager.folderCreatedSuccessfully', {name: newFolderName.trim()})); } setShowCreateFolder(false); setNewFolderName(''); onOperationComplete(); } catch (error: any) { toast.dismiss(loadingToast); onError(error?.response?.data?.error || t('fileManager.failedToCreateFolder')); } finally { setIsLoading(false); } }; const handleDelete = async () => { if (!deletePath || !sshSessionId) return; setIsLoading(true); const {toast} = await import('sonner'); 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); toast.dismiss(loadingToast); if (response?.toast) { toast[response.toast.type](response.toast.message); } else { onSuccess(t('fileManager.itemDeletedSuccessfully', {type: deleteIsDirectory ? t('fileManager.folder') : t('fileManager.file')})); } setShowDelete(false); setDeletePath(''); setDeleteIsDirectory(false); onOperationComplete(); } catch (error: any) { toast.dismiss(loadingToast); onError(error?.response?.data?.error || t('fileManager.failedToDeleteItem')); } finally { setIsLoading(false); } }; const handleRename = async () => { if (!renamePath || !newName.trim() || !sshSessionId) return; setIsLoading(true); const {toast} = await import('sonner'); 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()); toast.dismiss(loadingToast); if (response?.toast) { toast[response.toast.type](response.toast.message); } else { onSuccess(t('fileManager.itemRenamedSuccessfully', {type: renameIsDirectory ? t('fileManager.folder') : t('fileManager.file')})); } setShowRename(false); setRenamePath(''); setRenameIsDirectory(false); setNewName(''); onOperationComplete(); } catch (error: any) { toast.dismiss(loadingToast); onError(error?.response?.data?.error || t('fileManager.failedToRenameItem')); } finally { setIsLoading(false); } }; const openFileDialog = () => { fileInputRef.current?.click(); }; const handleFileSelect = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { setUploadFile(file); } }; const resetStates = () => { setShowUpload(false); setShowCreateFile(false); setShowCreateFolder(false); setShowDelete(false); setShowRename(false); setUploadFile(null); setNewFileName(''); setNewFolderName(''); setDeletePath(''); setDeleteIsDirectory(false); setRenamePath(''); setRenameIsDirectory(false); setNewName(''); }; if (!sshSessionId) { return (

{t('fileManager.connectToSsh')}

); } return (
{t('fileManager.currentPath')}: {currentPath}
{showUpload && (

{t('fileManager.uploadFileTitle')}

{t('fileManager.maxFileSize')}

{uploadFile ? (

{uploadFile.name}

{(uploadFile.size / 1024).toFixed(2)} KB

) : (

{t('fileManager.clickToSelectFile')}

)}
)} {showCreateFile && (

{t('fileManager.createNewFile')}

setNewFileName(e.target.value)} placeholder={t('placeholders.fileName')} className="bg-dark-bg-button border-2 border-dark-border-hover text-white text-sm" onKeyDown={(e) => e.key === 'Enter' && handleCreateFile()} />
)} {showCreateFolder && (

{t('fileManager.createNewFolder')}

setNewFolderName(e.target.value)} placeholder={t('placeholders.folderName')} className="bg-dark-bg-button border-2 border-dark-border-hover text-white text-sm" onKeyDown={(e) => e.key === 'Enter' && handleCreateFolder()} />
)} {showDelete && (

{t('fileManager.deleteItem')}

{t('fileManager.warningCannotUndo')}
setDeletePath(e.target.value)} placeholder={t('placeholders.fullPath')} className="bg-dark-bg-button border-2 border-dark-border-hover text-white text-sm" />
setDeleteIsDirectory(e.target.checked)} className="rounded border-dark-border-hover bg-dark-bg-button mt-0.5 flex-shrink-0" />
)} {showRename && (

{t('fileManager.renameItem')}

setRenamePath(e.target.value)} placeholder={t('placeholders.currentPath')} className="bg-dark-bg-button border-2 border-dark-border-hover text-white text-sm" />
setNewName(e.target.value)} placeholder={t('placeholders.newName')} className="bg-dark-bg-button border-2 border-dark-border-hover text-white text-sm" onKeyDown={(e) => e.key === 'Enter' && handleRename()} />
setRenameIsDirectory(e.target.checked)} className="rounded border-dark-border-hover bg-dark-bg-button mt-0.5 flex-shrink-0" />
)}
); }