diff --git a/ui/src/components/ChatInterface.tsx b/ui/src/components/ChatInterface.tsx index f2b5c1d9b1ae602eeb165c332376e27b42971877..30ba8375787b9080d04b0e144fd5a0aeef85a8d2 100644 --- a/ui/src/components/ChatInterface.tsx +++ b/ui/src/components/ChatInterface.tsx @@ -591,6 +591,7 @@ function ChatInterface({ const [diffViewerInitialCommit, setDiffViewerInitialCommit] = useState( undefined, ); + const [diffViewerCwd, setDiffViewerCwd] = useState(undefined); const [diffCommentText, setDiffCommentText] = useState(""); const [agentWorking, setAgentWorking] = useState(false); const [cancelling, setCancelling] = useState(false); @@ -1350,8 +1351,9 @@ function ChatInterface({ { + onOpenDiffViewer={(commit, cwd) => { setDiffViewerInitialCommit(commit); + setDiffViewerCwd(cwd); setShowDiffViewer(true); }} onCommentTextChange={setDiffCommentText} @@ -1825,14 +1827,16 @@ function ChatInterface({ {/* Diff Viewer */} { setShowDiffViewer(false); setDiffViewerInitialCommit(undefined); + setDiffViewerCwd(undefined); }} onCommentTextChange={setDiffCommentText} initialCommit={diffViewerInitialCommit} + onCwdChange={setDiffViewerCwd} /> {/* Version Checker Modal */} diff --git a/ui/src/components/DiffViewer.tsx b/ui/src/components/DiffViewer.tsx index 357705b92717be84b9e1f93a121b4b6068ebdd4e..5b9f91db6b42af6aa8b00aaf90ce8067282c244d 100644 --- a/ui/src/components/DiffViewer.tsx +++ b/ui/src/components/DiffViewer.tsx @@ -3,6 +3,7 @@ import type * as Monaco from "monaco-editor"; import { api } from "../services/api"; import { isDarkModeActive } from "../services/theme"; import { GitDiffInfo, GitFileInfo, GitFileDiff } from "../types"; +import DirectoryPickerModal from "./DirectoryPickerModal"; interface DiffViewerProps { cwd: string; @@ -10,6 +11,7 @@ interface DiffViewerProps { onClose: () => void; onCommentTextChange: (text: string) => void; initialCommit?: string; // If set, select this commit when opening + onCwdChange?: (cwd: string) => void; // Called when user picks a different git directory } // Icon components for cleaner JSX @@ -79,9 +81,17 @@ function loadMonaco(): Promise { type ViewMode = "comment" | "edit"; -function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit }: DiffViewerProps) { +function DiffViewer({ + cwd, + isOpen, + onClose, + onCommentTextChange, + initialCommit, + onCwdChange, +}: DiffViewerProps) { const [diffs, setDiffs] = useState([]); const [gitRoot, setGitRoot] = useState(null); + const [showDirPicker, setShowDirPicker] = useState(false); const [selectedDiff, setSelectedDiff] = useState(null); const [files, setFiles] = useState([]); const [selectedFile, setSelectedFile] = useState(null); @@ -904,6 +914,27 @@ function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit } ); + const dirButton = ( + + ); + return (
@@ -929,6 +960,7 @@ function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit } {commitSelector} {fileSelector}
+ {dirButton} @@ -944,6 +976,7 @@ function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit }
{navButtons} {modeToggle} + {dirButton} @@ -1072,6 +1105,18 @@ function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit }
)}
+ + {/* Directory picker for changing git directory */} + setShowDirPicker(false)} + onSelect={(path) => { + onCwdChange?.(path); + setShowDirPicker(false); + }} + initialPath={cwd} + foldersOnly + /> ); } diff --git a/ui/src/components/DirectoryPickerModal.tsx b/ui/src/components/DirectoryPickerModal.tsx index eb6210c70939d1ad340386370beacc4c43c1cbd4..1e255e3cc4c9f7e6a611d54c78a7b62a16fb4fcb 100644 --- a/ui/src/components/DirectoryPickerModal.tsx +++ b/ui/src/components/DirectoryPickerModal.tsx @@ -20,6 +20,7 @@ interface DirectoryPickerModalProps { onClose: () => void; onSelect: (path: string) => void; initialPath?: string; + foldersOnly?: boolean; // If true, only show directories (hide files) } function DirectoryPickerModal({ @@ -27,6 +28,7 @@ function DirectoryPickerModal({ onClose, onSelect, initialPath, + foldersOnly, }: DirectoryPickerModalProps) { const [inputPath, setInputPath] = useState(() => { if (!initialPath) return ""; @@ -173,6 +175,7 @@ function DirectoryPickerModal({ // Filter entries based on prefix (case-insensitive) const filteredEntries = displayDir?.entries.filter((entry) => { + if (foldersOnly && !entry.is_dir) return false; if (!filterPrefix) return true; return entry.name.toLowerCase().startsWith(filterPrefix.toLowerCase()); }) || []; diff --git a/ui/src/components/Message.tsx b/ui/src/components/Message.tsx index 08c359852b5d50db8192b5fe5a1955ac0ac7de45..c5038c0c7a98bd8cf24b6cffd617f61b308d53a3 100644 --- a/ui/src/components/Message.tsx +++ b/ui/src/components/Message.tsx @@ -28,7 +28,7 @@ interface ToolDisplay { interface MessageProps { message: MessageType; - onOpenDiffViewer?: (commit: string) => void; + onOpenDiffViewer?: (commit: string, cwd?: string) => void; onCommentTextChange?: (text: string) => void; } @@ -72,7 +72,7 @@ function GitInfoMessage({ onOpenDiffViewer, }: { message: MessageType; - onOpenDiffViewer?: (commit: string) => void; + onOpenDiffViewer?: (commit: string, cwd?: string) => void; }) { const [copied, setCopied] = useState(false); @@ -111,7 +111,7 @@ function GitInfoMessage({ const handleDiffClick = () => { if (commitHash && onOpenDiffViewer) { - onOpenDiffViewer(commitHash); + onOpenDiffViewer(commitHash, worktree || undefined); } }; diff --git a/ui/src/styles.css b/ui/src/styles.css index dfa8106c5949f17122e397e9ba30488dc6f47baf..ede174c8fd18d51e4563daf0f9c49d64651043a5 100644 --- a/ui/src/styles.css +++ b/ui/src/styles.css @@ -3502,6 +3502,26 @@ svg { font-size: 0.875rem; } +.diff-viewer-dir-btn { + width: 2rem; + height: 2rem; + border: none; + background: transparent; + color: var(--text-secondary); + cursor: pointer; + border-radius: 0.25rem; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + padding: 0; +} + +.diff-viewer-dir-btn:hover { + background: var(--bg-tertiary); + color: var(--text-primary); +} + .diff-viewer-close { width: 2rem; height: 2rem;