diff --git a/src/App.jsx b/src/App.jsx index b20afb4..eb3237f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -648,7 +648,7 @@ function AppContent() { )} {/* Main Content Area - Flexible */} -
+
{ - const isGrouped = prevMessage && prevMessage.type === message.type && - prevMessage.type === 'assistant' && - !prevMessage.isToolUse && !message.isToolUse; + const isGrouped = prevMessage && prevMessage.type === message.type && + ((prevMessage.type === 'assistant') || + (prevMessage.type === 'user') || + (prevMessage.type === 'tool') || + (prevMessage.type === 'error')); const messageRef = React.useRef(null); const [isExpanded, setIsExpanded] = React.useState(false); React.useEffect(() => { @@ -3217,7 +3219,7 @@ function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, mess {/* Input Area - Fixed Bottom */}
diff --git a/src/components/FileTree.jsx b/src/components/FileTree.jsx index 1048bdb..725ae7c 100644 --- a/src/components/FileTree.jsx +++ b/src/components/FileTree.jsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import { ScrollArea } from './ui/scroll-area'; import { Button } from './ui/button'; -import { Folder, FolderOpen, File, FileText, FileCode, List, TableProperties, Eye } from 'lucide-react'; +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'; @@ -14,6 +15,8 @@ function FileTree({ selectedProject }) { 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) { @@ -29,6 +32,51 @@ function FileTree({ selectedProject }) { } }, []); + // 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 { @@ -308,42 +356,67 @@ function FileTree({ selectedProject }) { return (
- {/* View Mode Toggle */} -
-

Files

-
- - - + {/* Header with Search and View Mode Toggle */} +
+
+

Files

+
+ + + +
+
+ + {/* Search Bar */} +
+ + setSearchQuery(e.target.value)} + className="pl-8 pr-8 h-8 text-sm" + /> + {searchQuery && ( + + )}
{/* Column Headers for Detailed View */} - {viewMode === 'detailed' && files.length > 0 && ( + {viewMode === 'detailed' && filteredFiles.length > 0 && (
Name
@@ -365,11 +438,21 @@ function FileTree({ selectedProject }) { Check if the project path is accessible

+ ) : filteredFiles.length === 0 && searchQuery ? ( +
+
+ +
+

No matches found

+

+ Try a different search term or clear the search +

+
) : (
- {viewMode === 'simple' && renderFileTree(files)} - {viewMode === 'compact' && renderCompactView(files)} - {viewMode === 'detailed' && renderDetailedView(files)} + {viewMode === 'simple' && renderFileTree(filteredFiles)} + {viewMode === 'compact' && renderCompactView(filteredFiles)} + {viewMode === 'detailed' && renderDetailedView(filteredFiles)}
)} diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx index 15884fe..4398cbc 100644 --- a/src/components/Settings.jsx +++ b/src/components/Settings.jsx @@ -1992,8 +1992,8 @@ function Settings({ isOpen, onClose, projects = [] }) { {/* Login Modal */} {showLoginModal && ( -
-
+
+

{loginProvider === 'claude' ? 'Claude CLI Login' : 'Cursor CLI Login'}