Skip to content

Dev #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 20, 2025
Merged

Dev #75

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 268 additions & 0 deletions Filepicker-Improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
# Filepicker Module Analysis and Improvement Recommendations

## Executive Summary

This document analyzes the filepicker implementation in tldw_chatbook and provides actionable recommendations for improvements. The analysis covers the current dual-implementation architecture (third-party `textual_fspicker` and custom `file_picker_dialog.py` wrapper), identifies pain points, and suggests both easy wins and more comprehensive improvements.

## Current Architecture Overview

### 1. Third-Party Component (`textual_fspicker`)
- **Location**: `tldw_chatbook/Third_Party/textual_fspicker/`
- **Components**:
- `FileOpen`: File opening dialog
- `FileSave`: File saving dialog
- `DirectoryNavigation`: Core navigation widget
- `DriveNavigation`: Windows drive selection
- `Filters`: File type filtering system

### 2. Custom Wrapper (`file_picker_dialog.py`)
- **Location**: `tldw_chatbook/Widgets/file_picker_dialog.py`
- **Purpose**: Evaluation-specific file picker dialogs
- **Classes**:
- `EvalFilePickerDialog`: Base modal dialog
- `TaskFilePickerDialog`: Task file selection
- `DatasetFilePickerDialog`: Dataset file selection
- `ExportFilePickerDialog`: Result export
- `QuickPickerWidget`: Inline file selection

## Identified Issues and Improvements

### 🏆 Easy Wins (Low effort, high impact)

#### 1. **Add Keyboard Shortcuts**
**Issue**: No keyboard shortcuts for common actions
**Solution**: Add bindings for:
```python
BINDINGS = [
Binding("ctrl+h", "toggle_hidden", "Toggle hidden files"),
Binding("ctrl+l", "focus_path_input", "Edit path directly"),
Binding("ctrl+d", "bookmark_current", "Bookmark directory"),
Binding("f5", "refresh", "Refresh directory"),
Binding("tab", "toggle_focus", "Switch focus"),
]
```
**Effort**: 2-3 hours
**Impact**: Significant UX improvement

#### 2. **Recent Files/Directories List**
**Issue**: Users must navigate from scratch each time
**Solution**: Add a recent locations dropdown
```python
class RecentLocations:
def __init__(self, max_items: int = 10):
self.recent: List[Path] = []
self.load_from_config()

def add(self, path: Path):
if path in self.recent:
self.recent.remove(path)
self.recent.insert(0, path)
self.recent = self.recent[:self.max_items]
self.save_to_config()
```
**Effort**: 3-4 hours
**Impact**: Major time-saver for users

#### 3. **Improve Path Display**
**Issue**: Current path display can be unclear/truncated
**Solution**: Add breadcrumb navigation
```python
class PathBreadcrumbs(Horizontal):
"""Clickable breadcrumb path navigation"""
def render_path(self, path: Path):
parts = path.parts
for i, part in enumerate(parts):
partial_path = Path(*parts[:i+1])
yield Button(part, classes="breadcrumb-button")
if i < len(parts) - 1:
yield Label("/", classes="breadcrumb-separator")
```
**Effort**: 4-5 hours
**Impact**: Better navigation clarity

#### 4. **File Preview Panel**
**Issue**: No way to preview file contents
**Solution**: Add optional preview pane for text/image files
```python
class FilePreview(Container):
def update_preview(self, file_path: Path):
if file_path.suffix in ['.txt', '.json', '.yaml', '.md']:
self.show_text_preview(file_path)
elif file_path.suffix in ['.png', '.jpg', '.webp']:
self.show_image_preview(file_path)
```
**Effort**: 4-5 hours
**Impact**: Reduces wrong file selections

#### 5. **Search Within Directory**
**Issue**: No search functionality for large directories
**Solution**: Add search input with real-time filtering
```python
@on(Input.Changed, "#search-input")
def filter_entries(self, event: Input.Changed):
search_term = event.value.lower()
for entry in self.directory_entries:
entry.visible = search_term in entry.name.lower()
```
**Effort**: 2-3 hours
**Impact**: Much faster file finding

### 🔨 Medium Improvements (Moderate effort, good impact)

#### 6. **Multi-file Selection**
**Issue**: Can only select one file at a time
**Solution**: Add checkbox mode for batch operations
```python
class MultiSelectFileOpen(FileOpen):
selected_files: reactive[Set[Path]] = reactive(set())

def toggle_selection(self, path: Path):
if path in self.selected_files:
self.selected_files.discard(path)
else:
self.selected_files.add(path)
```
**Effort**: 8-10 hours
**Impact**: Enables batch processing workflows

#### 7. **Bookmarks/Favorites System**
**Issue**: No way to save frequently used locations
**Solution**: Add persistent bookmarks sidebar
```python
class BookmarksPanel(Container):
def compose(self) -> ComposeResult:
yield ListView(id="bookmarks-list")
yield Button("+ Add Current", id="add-bookmark")

def load_bookmarks(self) -> List[Bookmark]:
return self.app.config.get("filepicker.bookmarks", [])
```
**Effort**: 6-8 hours
**Impact**: Significant workflow improvement

#### 8. **Performance: Lazy Loading**
**Issue**: Large directories load slowly
**Solution**: Implement virtual scrolling with batch loading
```python
class LazyDirectoryNavigation(DirectoryNavigation):
BATCH_SIZE = 100

async def load_entries_batch(self, start: int, end: int):
# Load only visible entries + buffer
entries = self.all_entries[start:end]
await self.update_display(entries)
```
**Effort**: 10-12 hours
**Impact**: Much better performance for large dirs

### 🚀 Major Improvements (Higher effort, transformative impact)

#### 9. **Unified Filepicker Architecture**
**Issue**: Dual implementation creates maintenance burden
**Solution**: Create single, extensible filepicker system
```python
class UnifiedFilePicker:
"""Single filepicker with plugin system for different contexts"""
def register_filter_preset(self, name: str, filters: Filters):
self.filter_presets[name] = filters

def register_validator(self, name: str, validator: Callable):
self.validators[name] = validator
```
**Effort**: 20-30 hours
**Impact**: Cleaner codebase, easier to extend

#### 10. **Drag and Drop Support**
**Issue**: No modern drag/drop functionality
**Solution**: Implement drop zones for file selection
```python
class DropZoneFilePicker(FilePicker):
def on_drop(self, event: DropEvent):
for file_path in event.files:
self.add_selected_file(file_path)
```
**Effort**: 15-20 hours
**Impact**: Modern UX expected by users

## Implementation Priority Matrix

### Phase 1: Quick Wins (1-2 weeks)
1. ✅ Keyboard shortcuts
2. ✅ Recent files list
3. ✅ Search within directory
4. ✅ Improve path display

### Phase 2: Enhanced UX (2-3 weeks)
5. ✅ File preview panel
6. ✅ Bookmarks system
7. ✅ Basic multi-selection

### Phase 3: Performance & Architecture (4-6 weeks)
8. ✅ Lazy loading implementation
9. ✅ Unified architecture refactor
10. ✅ Drag and drop support

## Code Quality Improvements

### Type Hints Enhancement
```python
# Before
def handle_file_selected(self, event):
self.selected_file = str(event.path)

# After
def handle_file_selected(self, event: FileOpen.FileSelected) -> None:
self.selected_file: str = str(event.path)
```

### Error Handling Improvements
```python
# Add specific exception types
class FilePickerError(Exception):
"""Base exception for filepicker errors"""

class InvalidPathError(FilePickerError):
"""Raised when path is invalid or inaccessible"""

class FilterError(FilePickerError):
"""Raised when file filter pattern is invalid"""
```

### Consistent Event System
```python
# Define standard events
class FilePickerEvents:
class FileSelected(Message):
path: Path

class DirectoryChanged(Message):
path: Path

class FilterChanged(Message):
filter: Filter
```

## Testing Recommendations

1. **Unit Tests**: Test each component in isolation
2. **Integration Tests**: Test dialog workflows
3. **Performance Tests**: Benchmark large directory handling
4. **Accessibility Tests**: Ensure keyboard navigation works

## Migration Strategy

1. **Backward Compatibility**: Keep existing APIs working
2. **Feature Flags**: Roll out new features gradually
3. **Documentation**: Update examples and guides
4. **Deprecation Path**: Clear timeline for old API removal

## Conclusion

The filepicker module has significant room for improvement. Starting with the easy wins will provide immediate user benefits while building toward a more comprehensive overhaul. The recommended phased approach balances quick improvements with long-term architectural benefits.

### Next Steps
1. Review and prioritize recommendations with team
2. Create detailed implementation tickets
3. Begin with Phase 1 easy wins
4. Gather user feedback after each phase
5. Iterate based on real-world usage patterns
Loading
Loading