import React, { useState, useEffect } from 'react'; import { ScrollArea } from './ui/scroll-area'; import { Button } from './ui/button'; import { Input } from './ui/input'; import { Folder, FolderOpen, File, FileText, FileCode, List, TableProperties, Eye, Search, X } from 'lucide-react'; import { cn } from '../lib/utils'; import CodeEditor from './CodeEditor'; import ImageViewer from './ImageViewer'; import { api } from '../utils/api'; function FileTree({ selectedProject }) { const [files, setFiles] = useState([]); const [loading, setLoading] = useState(false); const [expandedDirs, setExpandedDirs] = useState(new Set()); const [selectedFile, setSelectedFile] = useState(null); const [selectedImage, setSelectedImage] = useState(null); const [viewMode, setViewMode] = useState('detailed'); // 'simple', 'detailed', 'compact' const [searchQuery, setSearchQuery] = useState(''); const [filteredFiles, setFilteredFiles] = useState([]); useEffect(() => { if (selectedProject) { fetchFiles(); } }, [selectedProject]); // Load view mode preference from localStorage useEffect(() => { const savedViewMode = localStorage.getItem('file-tree-view-mode'); if (savedViewMode && ['simple', 'detailed', 'compact'].includes(savedViewMode)) { setViewMode(savedViewMode); } }, []); // Filter files based on search query useEffect(() => { if (!searchQuery.trim()) { setFilteredFiles(files); } else { const filtered = filterFiles(files, searchQuery.toLowerCase()); setFilteredFiles(filtered); // Auto-expand directories that contain matches const expandMatches = (items) => { items.forEach(item => { if (item.type === 'directory' && item.children && item.children.length > 0) { setExpandedDirs(prev => new Set(prev.add(item.path))); expandMatches(item.children); } }); }; expandMatches(filtered); } }, [files, searchQuery]); // Recursively filter files and directories based on search query const filterFiles = (items, query) => { return items.reduce((filtered, item) => { const matchesName = item.name.toLowerCase().includes(query); let filteredChildren = []; if (item.type === 'directory' && item.children) { filteredChildren = filterFiles(item.children, query); } // Include item if: // 1. It matches the search query, or // 2. It's a directory with matching children if (matchesName || filteredChildren.length > 0) { filtered.push({ ...item, children: filteredChildren }); } return filtered; }, []); }; const fetchFiles = async () => { setLoading(true); try { const response = await api.getFiles(selectedProject.name); if (!response.ok) { const errorText = await response.text(); console.error('❌ File fetch failed:', response.status, errorText); setFiles([]); return; } const data = await response.json(); setFiles(data); } catch (error) { console.error('❌ Error fetching files:', error); setFiles([]); } finally { setLoading(false); } }; const toggleDirectory = (path) => { const newExpanded = new Set(expandedDirs); if (newExpanded.has(path)) { newExpanded.delete(path); } else { newExpanded.add(path); } setExpandedDirs(newExpanded); }; // Change view mode and save preference const changeViewMode = (mode) => { setViewMode(mode); localStorage.setItem('file-tree-view-mode', mode); }; // Format file size const formatFileSize = (bytes) => { if (!bytes || bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; }; // Format date as relative time const formatRelativeTime = (date) => { if (!date) return '-'; const now = new Date(); const past = new Date(date); const diffInSeconds = Math.floor((now - past) / 1000); if (diffInSeconds < 60) return 'just now'; if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)} min ago`; if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)} hours ago`; if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 86400)} days ago`; return past.toLocaleDateString(); }; const renderFileTree = (items, level = 0) => { return items.map((item) => (
Check if the project path is accessible
Try a different search term or clear the search