polish: UI refinements, file preview enhancements, and Command K search#336
Conversation
Code Review - PR #336This PR adds three useful file preview enhancements. The implementation is solid overall, with good test coverage and adherence to the codebase patterns. Here's my detailed review: ✅ Strengths1. Excellent Test Coverage
2. Clean Prop ThreadingThe new 3. User Experience Considerations
|
…+Shift+Up/Down selection, and file change detection with reload banner - Add "Open in Default App" button to FilePreview toolbar using ExternalLink icon (consistent with tab context menu) - Add Cmd+Shift+Up/Down keyboard shortcuts for selection in file editor mode - Add file change detection: polls fs.stat every 3s for the active file tab, shows a dismissible banner with Reload button when file changes on disk - Banner warns about unsaved edits when user has pending changes - Wire handleReloadFileTab through App.tsx → useMainPanelProps → MainPanel → FilePreview - Reload clears edit content and refreshes from disk with updated lastModified timestamp
…der state Previously, "Visible Files" only excluded dotfiles, making the count nearly identical to "All Files." Now it uses fileExplorerExpanded to show only files in expanded folders, matching the file tree's actual visible state.
Add four new search-focused actions to the Quick Actions modal: - Search: Agents — opens and focuses the sidebar session filter - Search: Message History — opens the main panel output search - Search: Files — opens the file explorer filter in the right panel - Search: History — opens the history panel search in the right panel Lifts sessionFilterOpen (SessionList) and searchFilterOpen (HistoryPanel) from local component state to the Zustand uiStore so the Command K modal can trigger them. Uses setTimeout(50ms) to ensure the modal's focus trap releases before search inputs attempt to grab focus via autoFocus.
…on modal When Auto Run is in the stopping state, a red "Kill" pill appears next to the "STOPPING..." label. Clicking it opens a confirmation modal that warns about mid-execution termination before calling process.kill on the session.
…g formatting Previously, toggling to plain text mode called stripMarkdown() which removed URLs from links, heading markers, bold/italic syntax, and code fences — defeating the purpose of raw mode for copy-pasting.
…t behavior Align test expectations with actual runtime behavior — FilePreview polling test now accounts for initial mount stat call, and batch processor test adjusts doc2 read threshold for the recount-all-documents phase. Also adds missing Group type import in App.tsx.
d523273 to
bd54aeb
Compare
Pull Request Review: UI Polish and Feature EnhancementsThis is a well-crafted PR with comprehensive test coverage and thoughtful implementation. Here's my detailed feedback: ✅ StrengthsCode Quality
Implementation Highlights
🔍 Issues & Concerns1. Performance: File Change Detection PollingLocation: Issue: Every open file tab polls Concerns:
Recommendation: // Consider:
// 1. Only poll when tab is visible/active
// 2. Use a global interval that checks all tabs once (not per-tab intervals)
// 3. Increase interval when app is backgrounded (via Page Visibility API)
// 4. Add debouncing for stat calls on slow remotes
if (\!file?.path || \!lastModified || fileChangedOnDisk || \!isTabMode || \!isActive) return;2. Missing Type ImportLocation: The 3. Raw Markdown Mode: Terminology ConfusionLocation: Issue: The fix changes behavior from "strip markdown" to "show raw source", but the variable is still named
Recommendation: // Consider renaming for clarity:
chatRawTextMode → chatShowMarkdownSource
// or
chatRawTextMode → chatRawMarkdownMode4. Potential Race Condition in Search ActionsLocation: Issue: The 50ms Recommendation: // Use requestAnimationFrame + setTimeout for more reliability:
requestAnimationFrame(() => {
setTimeout(() => storeSetSessionFilterOpen(true), 50);
});
// Or use a slightly longer delay (100ms) to be safer5. File Reload: Potential Data LossLocation: Issue: When file has unsaved edits, the warning message is shown but reload is not prevented. Users might still accidentally click "Reload" and lose work. Recommendation: Add an additional confirmation modal when const handleReloadFile = useCallback(() => {
if (hasChanges) {
// Show ConfirmModal before reloading
setShowReloadConfirm(true);
} else {
setFileChangedOnDisk(false);
onReloadFile?.();
}
}, [hasChanges, onReloadFile]);6. Settings Modal Resize: Magic NumbersLocation: Issue: Dimensions changed from Recommendation: Extract to constants or use CSS variables for easier future adjustments: const SETTINGS_MODAL_WIDTH = 780;
const SETTINGS_MODAL_HEIGHT = 720;🔐 Security & Best Practices1. Path Injection Risk (Low)Location: window.maestro?.shell?.openExternal(`file://${file.path}`)Issue: If Recommendation: Validate/sanitize the path or use a dedicated IPC handler that validates paths server-side: // In main process (IPC handler):
const resolvedPath = path.resolve(filePath);
if (\!resolvedPath.startsWith(expectedBasePath)) {
throw new Error('Invalid file path');
}
shell.openExternal(`file://${resolvedPath}`);2. Error Handling: Silent FailuresLocation: Multiple
🎯 Performance ConsiderationsFile Search ModalLocation: The const expandedSet = useMemo(() =>
expandedFolders ? new Set(expandedFolders) : null,
[expandedFolders]
);
const visibleFiles = useMemo(() => {
if (\!expandedSet) return allFiles;
return flattenPreviewableFiles(fileTree, '', 0, expandedSet);
}, [fileTree, expandedSet, allFiles]);📝 Minor Suggestions
✨ Positive Callouts
🎯 SummaryRecommendation: Approve with minor fixes This is high-quality work that significantly improves the user experience. The main concern is the file change detection polling performance - I'd recommend addressing that before merging, especially the multi-tab scenario. The other issues are nice-to-haves that could be addressed in follow-up PRs. Priority Fixes:
Blocking: None - all issues are addressable post-merge if needed Great work overall! 🎉 |
PR Review: UI Refinements & File Preview EnhancementsSummaryOverall, this is a well-executed polish PR with strong attention to detail. The code quality is high, test coverage is comprehensive, and the implementation follows the codebase's established patterns. All 18,621 tests passing is excellent. ✅ StrengthsCode Quality
Implementation Highlights1. File Change Detection (FilePreview.tsx:712-746)Good:
Consideration: 3-second polling interval is reasonable for file change detection, but if many file tabs are open simultaneously, this could create significant IPC traffic. Consider:
2. File Search Filter Fix (FileSearchModal.tsx:168-195)The "Visible Files" filter now correctly respects folder expansion state. This is a significant UX improvement. Before: "Visible Files" meant "not hidden" (files not starting with .) Good:
3. Raw Markdown Mode Fix (TerminalOutput.tsx:740)The fix correctly removes the stripMarkdown() call, showing raw source instead of processed text. Before: stripMarkdown(filteredText) → "Heading" (# removed) This aligns with the feature's intent: Cmd+E should toggle between rendered and source view, not rendered and "stripped" view. 4. Command K Search Actions (QuickActionsModal.tsx:1034-1078)Clean implementation using uiStore to coordinate across panels without prop drilling. Good:
Minor suggestion: The 50ms magic number appears 4 times. Consider extracting to a constant like PANEL_TRANSITION_DELAY_MS = 50 5. Auto Run Kill Button (RightPanel.tsx:617-630)Proper confirmation flow with skull icon and destructive styling. Good:
🔍 Observations & Suggestions1. Settings Modal Resize (SettingsModal.tsx:1690)20% size increase (650×600 → 780×720) Observation: Consider testing on 1366×768 displays (common laptop resolution). 720px height + window chrome could overflow on smaller screens. 2. File Preview Polling PerformanceCurrent: Each open file tab polls independently every 3 seconds. Potential optimization for future: Centralized file watcher service that shares polling/watching across all tabs viewing the same file. Not critical for this PR, but worth considering if users report performance issues. 3. Open in Default App Button (FilePreview.tsx:1877-1885)Security consideration: File paths should be URL-encoded to handle special characters correctly: Example edge case: /path/with spaces/file#name.txt → malformed URL without encoding Also: Consider Windows path handling (C:\path\to\file.txt → file:///C:/path/to/file.txt) 4. Test HygieneThe test cleanup pattern is excellent - resetting uiStore state in beforeEach and cleanup in useEffect returns. This prevents test pollution. Well done. 🐛 Potential Issues1. File Reload Race Condition (App.tsx:5493)Between reading the file and reading the stat, the file could be modified again. The stat.modifiedAt might be newer than the content you just read, leading to an immediate "file changed" notification after reload. Suggested Fix: Read stat first, then content, then stat again to verify:
This is a rare edge case but could cause user confusion. 2. Missing Keyboard Handler CleanupIn useMainKeyboardHandler.test.ts, verify that renderHook from @testing-library/react automatically cleans up event listeners between tests. 🔒 SecurityFile Path InjectionThe shell.openExternal() call with user-controlled file paths is generally safe since it's from the local file tree, but:
📊 PerformanceGood Practices Observed:
Considerations:
🎯 Test CoverageExcellent coverage across the board:
All tests properly:
📝 Minor Code Quality Notes
🎨 Adherence to CLAUDE.md Guidelines✅ Tabs for indentation - Maintained throughout 🚀 RecommendationsMust Fix (before merge):
Should Consider (follow-up):
Nice to Have:
✨ Final VerdictApproved with minor suggestions. This is high-quality work that demonstrates strong understanding of React best practices, the codebase architecture, and testing requirements. The features are well-implemented and the test coverage is exemplary. Estimated Risk: Low - comprehensive tests, conservative changes, proper error handling Recommendation: Merge after addressing the URL encoding concern in "Open in Default App". The reload race condition is worth noting but likely acceptable as-is for this release. Great work! 🎉 |
…fileExplorerStore Merge origin/main into 0.15.0-polish, resolving App.tsx import conflict (removed unused Group and GroupChatMessage type imports). Migrated QuickActionsModal's fileTreeFilterOpen usage from deprecated uiStore to fileExplorerStore to align with main's refactored architecture.
Code Review: PR #336 - UI Polish & Feature Enhancements for 0.15.0Thank you for this comprehensive set of UI improvements! Overall, this is a well-structured PR with excellent test coverage. Here's my detailed feedback: ✅ Strengths
🔍 Issues & Concerns1. Performance: File Polling Interval (Medium Priority)Problem: 3-second polling for every active file tab can create performance issues:
Location: src/renderer/components/FilePreview.tsx:1244 Recommendations:
2. Error Handling: Silent Failures (Medium Priority)Multiple locations swallow errors without user feedback at FilePreview.tsx:1251 and App.tsx:3799 Problem:
Recommendations:
3. Race Condition: Reload During Edit (High Priority)Location: src/renderer/App.tsx:3804 Problem:
Recommendation:
4. Memory Leak Potential: Polling Not Stopped (Low Priority)Location: src/renderer/components/FilePreview.tsx:1244 Analysis:
Recommendation:
5. UX Issue: "Open in Default App" for SSH (Low Priority)Good: You correctly hide this button for SSH sessions (commit 0874a96). Suggestion:
6. Type Safety: Optional Chaining Overuse (Low Priority)Location: src/renderer/components/FilePreview.tsx:1275 Observation:
Recommendation: Add error handling or disable the button if the API is unavailable 7. Zustand Store Cleanup Pattern (Low Priority)Good: You correctly clean up store state on unmount in HistoryPanel.tsx:1452 Concern:
8. Command K Search: setTimeout Magic Number (Low Priority)Location: src/renderer/components/QuickActionsModal.tsx:1550 Problem:
Recommendation:
🎯 Code Style & Conventions✅ Adheres to CLAUDE.md:
✅ Test Quality:
🚀 Suggestions for Follow-up
📊 Summary
✅ Recommendation: Approve with Minor RevisionsThis PR is well-executed and ready to merge with minor improvements: Must Fix Before Merge:
Nice to Have (can be follow-up PRs):
Great work on this feature set! The file change detection and Kill button are valuable additions that will improve the user experience significantly. Reviewed by: Claude Code Agent |
Summary
A collection of UI polish and feature enhancements for the 0.15.0 release:
Cmd+Shift+Up/Downfile selection in the Right Bar, and automatic file change detection with a reload bannerCmd+Enow correctly shows source markdown text instead of stripping formattingChanges
FilePreview.tsx,MainPanel.tsx,RightPanel.tsxCmd+Shift+Up/Downselection, file change detection with reload bannerQuickActionsModal.tsx,App.tsxAppModals.tsx,App.tsxTerminalOutput.tsxCmd+E) now preserves source textFileSearchModal.tsxSettingsModal.tsxuseMainKeyboardHandler.tsCmd+Shift+Up/Downfor file selectionuiStore.tsCommits
776da736feat: add file preview enhancements — Open in Default App button, Cmd+Shift+Up/Down selection, and file change detection with reload banner30eb565ffix: fuzzy file search Visible Files filter now respects expanded folder state972ba899feat: add Search actions to Command K menu for all panels5231be0afeat: add Kill pill button to Auto Run stopping state with confirmation modal38273de2fix: raw markdown mode (⌘E) now shows source text instead of stripping formatting1e7803b9fix: update tests for file preview polling and batch processor recount behaviord523273cfix: increase settings modal dimensions by 20% (650×600 → 780×720)Test Plan
npm run lint)npm run lint:eslint)npm run test) — 434 test files, 0 failuresCmd+Eshows raw markdown source in AI TerminalCmd+Shift+Up/Downnavigates file preview tabs