import { useState } from 'react'; import { useParams } from 'react-router'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Folder, FileText, ArrowUp, Trash2, Plus, Download, Upload, Save, X, } from 'lucide-react'; import { api } from '@/lib/api'; import { formatBytes } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogClose, } from '@/components/ui/dialog'; interface FileEntry { name: string; path: string; isDirectory: boolean; size: number; modifiedAt: number; } export function FilesPage() { const { orgId, serverId } = useParams(); const queryClient = useQueryClient(); const [currentPath, setCurrentPath] = useState('/'); const [editingFile, setEditingFile] = useState<{ path: string; content: string } | null>(null); const [newFileName, setNewFileName] = useState(''); const [showNewFile, setShowNewFile] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const filesQuery = useQuery({ queryKey: ['files', orgId, serverId, currentPath], queryFn: () => api.get<{ files: FileEntry[] }>( `/organizations/${orgId}/servers/${serverId}/files`, { path: currentPath }, ), enabled: !editingFile, }); const deleteMutation = useMutation({ mutationFn: (paths: string[]) => api.post(`/organizations/${orgId}/servers/${serverId}/files/delete`, { paths }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['files', orgId, serverId, currentPath] }); setDeleteTarget(null); }, }); const saveMutation = useMutation({ mutationFn: ({ path, data }: { path: string; data: string }) => api.post(`/organizations/${orgId}/servers/${serverId}/files/write`, { path, data }), onSuccess: () => { setEditingFile(null); queryClient.invalidateQueries({ queryKey: ['files', orgId, serverId, currentPath] }); }, }); const createFileMutation = useMutation({ mutationFn: ({ path, data }: { path: string; data: string }) => api.post(`/organizations/${orgId}/servers/${serverId}/files/write`, { path, data }), onSuccess: () => { setShowNewFile(false); setNewFileName(''); queryClient.invalidateQueries({ queryKey: ['files', orgId, serverId, currentPath] }); }, }); const openFile = async (file: FileEntry) => { if (file.isDirectory) { setCurrentPath(file.path); return; } const res = await api.get<{ data: string }>( `/organizations/${orgId}/servers/${serverId}/files/read`, { path: file.path }, ); setEditingFile({ path: file.path, content: res.data }); }; const goUp = () => { if (currentPath === '/') return; const parts = currentPath.split('/').filter(Boolean); parts.pop(); setCurrentPath('/' + parts.join('/')); }; const breadcrumbs = currentPath.split('/').filter(Boolean); const files = filesQuery.data?.files ?? []; return (
{editingFile ? ( {editingFile.path}