Skip to content

Commit 00e5b17

Browse files
committed
🤖 Restore ReviewPanel and FileTree from good state
1 parent fc9c414 commit 00e5b17

File tree

2 files changed

+267
-570
lines changed

2 files changed

+267
-570
lines changed

src/components/RightSidebar/CodeReview/FileTree.tsx

Lines changed: 97 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -3,140 +3,10 @@
33
*/
44

55
import React from "react";
6-
import styled from "@emotion/styled";
76
import type { FileTreeNode } from "@/utils/git/numstatParser";
87
import { usePersistedState } from "@/hooks/usePersistedState";
98
import { getFileTreeExpandStateKey } from "@/constants/storage";
10-
11-
const TreeContainer = styled.div`
12-
flex: 1;
13-
min-height: 0;
14-
padding: 12px;
15-
overflow-y: auto;
16-
font-family: var(--font-monospace);
17-
font-size: 12px;
18-
`;
19-
20-
const TreeNode = styled.div<{ depth: number; isSelected: boolean }>`
21-
padding: 4px 8px;
22-
padding-left: ${(props) => props.depth * 16 + 8}px;
23-
cursor: pointer;
24-
user-select: none;
25-
display: flex;
26-
align-items: center;
27-
gap: 8px;
28-
background: ${(props) => (props.isSelected ? "rgba(100, 150, 255, 0.2)" : "transparent")};
29-
border-radius: 4px;
30-
margin: 2px 0;
31-
32-
&:hover {
33-
background: ${(props) =>
34-
props.isSelected ? "rgba(100, 150, 255, 0.2)" : "rgba(255, 255, 255, 0.05)"};
35-
}
36-
`;
37-
38-
const FileName = styled.span<{ isFullyRead?: boolean; isUnknownState?: boolean }>`
39-
color: #ccc;
40-
flex: 1;
41-
${(props) =>
42-
props.isFullyRead &&
43-
`
44-
color: #666;
45-
text-decoration: line-through;
46-
text-decoration-color: var(--color-read);
47-
text-decoration-thickness: 2px;
48-
`}
49-
${(props) =>
50-
props.isUnknownState &&
51-
!props.isFullyRead &&
52-
`
53-
color: #666;
54-
`}
55-
`;
56-
57-
const DirectoryName = styled.span<{ isFullyRead?: boolean; isUnknownState?: boolean }>`
58-
color: #888;
59-
flex: 1;
60-
${(props) =>
61-
props.isFullyRead &&
62-
`
63-
color: #666;
64-
text-decoration: line-through;
65-
text-decoration-color: var(--color-read);
66-
text-decoration-thickness: 2px;
67-
`}
68-
${(props) =>
69-
props.isUnknownState &&
70-
!props.isFullyRead &&
71-
`
72-
color: #666;
73-
`}
74-
`;
75-
76-
const DirectoryStats = styled.span<{ isOpen: boolean }>`
77-
display: flex;
78-
gap: 8px;
79-
font-size: 11px;
80-
color: ${(props) => (props.isOpen ? "#666" : "inherit")};
81-
opacity: 0.7;
82-
`;
83-
84-
const Stats = styled.span`
85-
display: flex;
86-
gap: 8px;
87-
font-size: 11px;
88-
`;
89-
90-
const Additions = styled.span`
91-
color: #4ade80;
92-
`;
93-
94-
const Deletions = styled.span`
95-
color: #f87171;
96-
`;
97-
98-
const ToggleIcon = styled.span<{ isOpen: boolean }>`
99-
width: 12px;
100-
display: inline-block;
101-
transform: ${(props) => (props.isOpen ? "rotate(90deg)" : "rotate(0deg)")};
102-
transition: transform 0.2s ease;
103-
`;
104-
105-
const ClearButton = styled.button`
106-
padding: 2px 8px;
107-
background: transparent;
108-
color: #888;
109-
border: none;
110-
border-radius: 3px;
111-
font-size: 11px;
112-
cursor: pointer;
113-
transition: all 0.2s ease;
114-
font-family: var(--font-primary);
115-
margin-left: auto;
116-
117-
&:hover {
118-
background: rgba(255, 255, 255, 0.05);
119-
color: #ccc;
120-
}
121-
`;
122-
123-
const TreeHeader = styled.div`
124-
padding: 8px 12px;
125-
border-bottom: 1px solid #3e3e42;
126-
font-size: 12px;
127-
font-weight: 500;
128-
color: #ccc;
129-
font-family: var(--font-primary);
130-
display: flex;
131-
align-items: center;
132-
gap: 8px;
133-
`;
134-
135-
const EmptyState = styled.div`
136-
padding: 20px;
137-
color: #888;
138-
text-align: center;
139-
`;
9+
import { cn } from "@/lib/utils";
14010

14111
/**
14212
* Compute read status for a directory by recursively checking all descendant files
@@ -185,6 +55,7 @@ const TreeNodeContent: React.FC<{
18555
depth: number;
18656
selectedPath: string | null;
18757
onSelectFile: (path: string | null) => void;
58+
commonPrefix: string | null;
18859
getFileReadStatus?: (filePath: string) => { total: number; read: number } | null;
18960
expandStateMap: Record<string, boolean>;
19061
setExpandStateMap: (
@@ -195,6 +66,7 @@ const TreeNodeContent: React.FC<{
19566
depth,
19667
selectedPath,
19768
onSelectFile,
69+
commonPrefix,
19870
getFileReadStatus,
19971
expandStateMap,
20072
setExpandStateMap,
@@ -254,48 +126,83 @@ const TreeNodeContent: React.FC<{
254126

255127
return (
256128
<>
257-
<TreeNode depth={depth} isSelected={isSelected} onClick={handleClick}>
129+
<div
130+
className={cn(
131+
"py-1 px-2 cursor-pointer select-none flex items-center gap-2 rounded my-0.5",
132+
isSelected ? "bg-[rgba(100,150,255,0.2)]" : "bg-transparent hover:bg-white/5"
133+
)}
134+
style={{ paddingLeft: `${depth * 16 + 8}px` }}
135+
onClick={handleClick}
136+
>
258137
{node.isDirectory ? (
259138
<>
260-
<ToggleIcon isOpen={isOpen} data-toggle onClick={handleToggleClick}>
139+
<span
140+
className="w-3 inline-block transition-transform duration-200"
141+
style={{ transform: isOpen ? "rotate(90deg)" : "rotate(0deg)" }}
142+
data-toggle
143+
onClick={handleToggleClick}
144+
>
261145
262-
</ToggleIcon>
263-
<DirectoryName isFullyRead={isFullyRead} isUnknownState={isUnknownState}>
146+
</span>
147+
<span
148+
className={cn(
149+
"flex-1",
150+
isFullyRead &&
151+
"text-[#666] line-through [text-decoration-color:var(--color-read)] [text-decoration-thickness:2px]",
152+
isUnknownState && !isFullyRead && "text-[#666]",
153+
!isFullyRead && !isUnknownState && "text-[#888]"
154+
)}
155+
>
264156
{node.name || "/"}
265-
</DirectoryName>
157+
</span>
266158
{node.totalStats &&
267159
(node.totalStats.additions > 0 || node.totalStats.deletions > 0) && (
268-
<DirectoryStats isOpen={isOpen}>
160+
<span
161+
className="flex gap-2 text-[11px] opacity-70"
162+
style={{ color: isOpen ? "#666" : "inherit" }}
163+
>
269164
{node.totalStats.additions > 0 &&
270165
(isOpen ? (
271166
<span>+{node.totalStats.additions}</span>
272167
) : (
273-
<Additions>+{node.totalStats.additions}</Additions>
168+
<span className="text-[#4ade80]">+{node.totalStats.additions}</span>
274169
))}
275170
{node.totalStats.deletions > 0 &&
276171
(isOpen ? (
277172
<span>-{node.totalStats.deletions}</span>
278173
) : (
279-
<Deletions>-{node.totalStats.deletions}</Deletions>
174+
<span className="text-[#f87171]">-{node.totalStats.deletions}</span>
280175
))}
281-
</DirectoryStats>
176+
</span>
282177
)}
283178
</>
284179
) : (
285180
<>
286181
<span style={{ width: "12px" }} />
287-
<FileName isFullyRead={isFullyRead} isUnknownState={isUnknownState}>
182+
<span
183+
className={cn(
184+
"flex-1",
185+
isFullyRead &&
186+
"text-[#666] line-through [text-decoration-color:var(--color-read)] [text-decoration-thickness:2px]",
187+
isUnknownState && !isFullyRead && "text-[#666]",
188+
!isFullyRead && !isUnknownState && "text-[#ccc]"
189+
)}
190+
>
288191
{node.name}
289-
</FileName>
192+
</span>
290193
{node.stats && (
291-
<Stats>
292-
{node.stats.additions > 0 && <Additions>+{node.stats.additions}</Additions>}
293-
{node.stats.deletions > 0 && <Deletions>-{node.stats.deletions}</Deletions>}
294-
</Stats>
194+
<span className="flex gap-2 text-[11px]">
195+
{node.stats.additions > 0 && (
196+
<span className="text-[#4ade80]">+{node.stats.additions}</span>
197+
)}
198+
{node.stats.deletions > 0 && (
199+
<span className="text-[#f87171]">-{node.stats.deletions}</span>
200+
)}
201+
</span>
295202
)}
296203
</>
297204
)}
298-
</TreeNode>
205+
</div>
299206

300207
{node.isDirectory &&
301208
isOpen &&
@@ -306,6 +213,7 @@ const TreeNodeContent: React.FC<{
306213
depth={depth + 1}
307214
selectedPath={selectedPath}
308215
onSelectFile={onSelectFile}
216+
commonPrefix={commonPrefix}
309217
getFileReadStatus={getFileReadStatus}
310218
expandStateMap={expandStateMap}
311219
setExpandStateMap={setExpandStateMap}
@@ -320,6 +228,7 @@ interface FileTreeExternalProps {
320228
selectedPath: string | null;
321229
onSelectFile: (path: string | null) => void;
322230
isLoading?: boolean;
231+
commonPrefix?: string | null;
323232
getFileReadStatus?: (filePath: string) => { total: number; read: number } | null;
324233
workspaceId: string;
325234
}
@@ -329,6 +238,7 @@ export const FileTree: React.FC<FileTreeExternalProps> = ({
329238
selectedPath,
330239
onSelectFile,
331240
isLoading = false,
241+
commonPrefix = null,
332242
getFileReadStatus,
333243
workspaceId,
334244
}) => {
@@ -339,32 +249,62 @@ export const FileTree: React.FC<FileTreeExternalProps> = ({
339249
{ listener: true }
340250
);
341251

252+
// Find the node at the common prefix path to start rendering from
253+
const startNode = React.useMemo(() => {
254+
if (!commonPrefix || !root) return root;
255+
256+
// Navigate to the node at the common prefix path
257+
const parts = commonPrefix.split("/");
258+
let current = root;
259+
260+
for (const part of parts) {
261+
const child = current.children.find((c) => c.name === part);
262+
if (!child) return root; // Fallback if path not found
263+
current = child;
264+
}
265+
266+
return current;
267+
}, [root, commonPrefix]);
268+
342269
return (
343270
<>
344-
<TreeHeader>
271+
<div className="py-2 px-3 border-b border-[#3e3e42] text-xs font-medium text-[#ccc] font-primary flex items-center gap-2">
345272
<span>Files Changed</span>
346-
{selectedPath && <ClearButton onClick={() => onSelectFile(null)}>Clear filter</ClearButton>}
347-
</TreeHeader>
348-
<TreeContainer>
349-
{isLoading && !root ? (
350-
<EmptyState>Loading file tree...</EmptyState>
351-
) : root ? (
352-
root.children.map((child) => (
273+
{selectedPath && (
274+
<button
275+
className="py-0.5 px-2 bg-transparent text-[#888] border-none rounded-[3px] text-[11px] cursor-pointer transition-all duration-200 font-primary ml-auto hover:bg-white/5 hover:text-[#ccc]"
276+
onClick={() => onSelectFile(null)}
277+
>
278+
Clear filter
279+
</button>
280+
)}
281+
</div>
282+
{commonPrefix && (
283+
<div className="py-1.5 px-3 bg-[#1e1e1e] border-b border-[#3e3e42] text-[11px] text-[#888] font-monospace">
284+
{commonPrefix}/
285+
</div>
286+
)}
287+
<div className="flex-1 min-h-0 p-3 overflow-y-auto font-monospace text-xs">
288+
{isLoading && !startNode ? (
289+
<div className="py-5 text-[#888] text-center">Loading file tree...</div>
290+
) : startNode ? (
291+
startNode.children.map((child) => (
353292
<TreeNodeContent
354293
key={child.path}
355294
node={child}
356295
depth={0}
357296
selectedPath={selectedPath}
358297
onSelectFile={onSelectFile}
298+
commonPrefix={commonPrefix}
359299
getFileReadStatus={getFileReadStatus}
360300
expandStateMap={expandStateMap}
361301
setExpandStateMap={setExpandStateMap}
362302
/>
363303
))
364304
) : (
365-
<EmptyState>No files changed</EmptyState>
305+
<div className="py-5 text-[#888] text-center">No files changed</div>
366306
)}
367-
</TreeContainer>
307+
</div>
368308
</>
369309
);
370310
};

0 commit comments

Comments
 (0)