Skip to content
Merged
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
2 changes: 1 addition & 1 deletion docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ This ensures transparency about AI-generated contributions.

## PR Management

**Prefer to reuse existing PRs** by force-pushing to the same branch, even if the branch name becomes irrelevant. Avoid closing and recreating PRs unnecessarily - PR spam clutters the repository history.
**Prefer to reuse existing PRs** by force-pushing to the same branch, even if the branch name becomes irrelevant. Avoid closing and recreating PRs unnecessarily - PR spam clutters the repository history. **Never close PRs without explicit user instruction.** Always force-push to the existing branch instead of creating new PRs.

After submitting or updating PRs, **always check merge status**:

Expand Down
147 changes: 75 additions & 72 deletions src/components/RightSidebar/CodeReview/ReviewPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -555,68 +555,85 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
Loading diff...
</div>
) : (
<div className="flex min-h-0 flex-1 flex-row overflow-hidden @[800px]:flex-col">
<div className="order-1 flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
{truncationWarning && (
<div className="bg-warning/10 border-warning/30 text-warning mx-3 my-3 flex items-center gap-1.5 rounded border px-3 py-1.5 text-[10px] leading-[1.3] before:text-xs before:content-['⚠️']">
{truncationWarning}
</div>
)}
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
{truncationWarning && (
<div className="bg-warning/10 border-warning/30 text-warning mx-3 my-3 flex items-center gap-1.5 rounded border px-3 py-1.5 text-[10px] leading-[1.3] before:text-xs before:content-['⚠️']">
{truncationWarning}
</div>
)}

{/* Search bar - always visible at top, not sticky */}
<div className="border-border-light bg-separator border-b px-3 py-2">
<div className="border-border-light bg-dark hover:border-border-gray focus-within:border-accent focus-within:hover:border-accent flex items-stretch overflow-hidden rounded border transition-[border-color] duration-150">
<input
ref={searchInputRef}
type="text"
placeholder={`Search in files and hunks... (${formatKeybind(KEYBINDS.FOCUS_REVIEW_SEARCH)})`}
value={searchState.input}
onChange={(e) => setSearchState({ ...searchState, input: e.target.value })}
className="text-foreground placeholder:text-dim focus:bg-separator flex h-full flex-1 items-center border-none bg-transparent px-2.5 py-1.5 font-sans text-xs leading-[1.4] outline-none"
/>
<TooltipWrapper inline>
<button
className={cn(
"py-1.5 px-2.5 border-none border-l border-light text-[11px] font-monospace font-semibold leading-[1.4] cursor-pointer outline-none transition-all duration-150 whitespace-nowrap flex items-center h-full",
searchState.useRegex
? "bg-review-bg-blue text-accent-light shadow-[inset_0_0_0_1px_rgba(77,184,255,0.4)] hover:bg-review-bg-info hover:text-accent-light"
: "bg-transparent text-subtle hover:bg-separator hover:text-foreground",
"active:translate-y-px"
)}
onClick={() =>
setSearchState({ ...searchState, useRegex: !searchState.useRegex })
}
>
.*
</button>
<Tooltip position="bottom">
{searchState.useRegex ? "Using regex search" : "Using substring search"}
</Tooltip>
</TooltipWrapper>
<TooltipWrapper inline>
<button
className={cn(
"py-1.5 px-2.5 border-none border-l border-light text-[11px] font-monospace font-semibold leading-[1.4] cursor-pointer outline-none transition-all duration-150 whitespace-nowrap flex items-center h-full",
searchState.matchCase
? "bg-review-bg-blue text-accent-light shadow-[inset_0_0_0_1px_rgba(77,184,255,0.4)] hover:bg-review-bg-info hover:text-accent-light"
: "bg-transparent text-subtle hover:bg-separator hover:text-foreground",
"active:translate-y-px"
)}
onClick={() =>
setSearchState({ ...searchState, matchCase: !searchState.matchCase })
}
>
Aa
</button>
<Tooltip position="bottom">
{searchState.matchCase
? "Match case (case-sensitive)"
: "Ignore case (case-insensitive)"}
</Tooltip>
</TooltipWrapper>
</div>
</div>

<div className="border-border-light bg-separator border-b px-3 py-2">
<div className="border-border-light bg-dark hover:border-border-gray focus-within:border-accent focus-within:hover:border-accent flex items-stretch overflow-hidden rounded border transition-[border-color] duration-150">
<input
ref={searchInputRef}
type="text"
placeholder={`Search in files and hunks... (${formatKeybind(KEYBINDS.FOCUS_REVIEW_SEARCH)})`}
value={searchState.input}
onChange={(e) => setSearchState({ ...searchState, input: e.target.value })}
className="text-foreground placeholder:text-dim focus:bg-separator flex h-full flex-1 items-center border-none bg-transparent px-2.5 py-1.5 font-sans text-xs leading-[1.4] outline-none"
{/* Single scrollable area containing both file tree and hunks */}
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto">
{/* FileTree at the top */}
{(fileTree ?? isLoadingTree) && (
<div className="border-border-light flex w-full flex-[0_0_auto] flex-col overflow-hidden border-b">
<FileTree
root={fileTree}
selectedPath={selectedFilePath}
onSelectFile={setSelectedFilePath}
isLoading={isLoadingTree}
getFileReadStatus={getFileReadStatus}
workspaceId={workspaceId}
/>
<TooltipWrapper inline>
<button
className={cn(
"py-1.5 px-2.5 border-none border-l border-light text-[11px] font-monospace font-semibold leading-[1.4] cursor-pointer outline-none transition-all duration-150 whitespace-nowrap flex items-center h-full",
searchState.useRegex
? "bg-review-bg-blue text-accent-light shadow-[inset_0_0_0_1px_rgba(77,184,255,0.4)] hover:bg-review-bg-info hover:text-accent-light"
: "bg-transparent text-subtle hover:bg-separator hover:text-foreground",
"active:translate-y-px"
)}
onClick={() =>
setSearchState({ ...searchState, useRegex: !searchState.useRegex })
}
>
.*
</button>
<Tooltip position="bottom">
{searchState.useRegex ? "Using regex search" : "Using substring search"}
</Tooltip>
</TooltipWrapper>
<TooltipWrapper inline>
<button
className={cn(
"py-1.5 px-2.5 border-none border-l border-light text-[11px] font-monospace font-semibold leading-[1.4] cursor-pointer outline-none transition-all duration-150 whitespace-nowrap flex items-center h-full",
searchState.matchCase
? "bg-review-bg-blue text-accent-light shadow-[inset_0_0_0_1px_rgba(77,184,255,0.4)] hover:bg-review-bg-info hover:text-accent-light"
: "bg-transparent text-subtle hover:bg-separator hover:text-foreground",
"active:translate-y-px"
)}
onClick={() =>
setSearchState({ ...searchState, matchCase: !searchState.matchCase })
}
>
Aa
</button>
<Tooltip position="bottom">
{searchState.matchCase
? "Match case (case-sensitive)"
: "Ignore case (case-insensitive)"}
</Tooltip>
</TooltipWrapper>
</div>
</div>
)}

<div className="min-h-0 flex-1 overflow-y-auto p-3">
{/* Hunks below the file tree */}
<div className="flex flex-[0_0_auto] flex-col p-3">
{hunks.length === 0 ? (
<div className="text-muted flex flex-col items-center justify-start gap-3 px-6 pt-12 pb-6 text-center">
<div className="text-foreground text-base font-medium">No changes found</div>
Expand Down Expand Up @@ -691,20 +708,6 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
)}
</div>
</div>

{/* FileTree positioning handled by CSS order property */}
{(fileTree ?? isLoadingTree) && (
<div className="border-border-light @[800px]:border-border-light order-2 flex min-h-0 w-80 shrink-0 flex-col overflow-hidden border-l @[800px]:order-0 @[800px]:h-auto @[800px]:w-full @[800px]:flex-[0_0_auto] @[800px]:border-b @[800px]:border-l-0">
<FileTree
root={fileTree}
selectedPath={selectedFilePath}
onSelectFile={setSelectedFilePath}
isLoading={isLoadingTree}
getFileReadStatus={getFileReadStatus}
workspaceId={workspaceId}
/>
</div>
)}
</div>
)}
</div>
Expand Down