11import { FileIcon } from "@components/ui/FileIcon" ;
22import { PanelMessage } from "@components/ui/PanelMessage" ;
3+ import { Tooltip } from "@components/ui/Tooltip" ;
34import { isDiffTabActiveInTree , usePanelLayoutStore } from "@features/panels" ;
45import { usePendingPermissionsForTask } from "@features/sessions/stores/sessionStore" ;
56import { useCwd } from "@features/sidebar/hooks/useCwd" ;
@@ -18,7 +19,6 @@ import {
1819 Flex ,
1920 IconButton ,
2021 Text ,
21- Tooltip ,
2222} from "@radix-ui/themes" ;
2323import { trpcVanilla } from "@renderer/trpc/client" ;
2424import type { ChangedFile , GitFileStatus , Task } from "@shared/types" ;
@@ -45,20 +45,21 @@ interface ChangedFileItemProps {
4545
4646function getStatusIndicator ( status : GitFileStatus ) : {
4747 label : string ;
48+ fullLabel : string ;
4849 color : "green" | "orange" | "red" | "blue" | "gray" ;
4950} {
5051 switch ( status ) {
5152 case "added" :
5253 case "untracked" :
53- return { label : "A" , color : "green" } ;
54+ return { label : "A" , fullLabel : "Added" , color : "green" } ;
5455 case "deleted" :
55- return { label : "D" , color : "red" } ;
56+ return { label : "D" , fullLabel : "Deleted" , color : "red" } ;
5657 case "modified" :
57- return { label : "M" , color : "orange" } ;
58+ return { label : "M" , fullLabel : "Modified" , color : "orange" } ;
5859 case "renamed" :
59- return { label : "R" , color : "blue" } ;
60+ return { label : "R" , fullLabel : "Renamed" , color : "blue" } ;
6061 default :
61- return { label : "?" , color : "gray" } ;
62+ return { label : "?" , fullLabel : "Unknown" , color : "gray" } ;
6263 }
6364}
6465
@@ -206,156 +207,170 @@ function ChangedFileItem({
206207 const hasLineStats =
207208 file . linesAdded !== undefined || file . linesRemoved !== undefined ;
208209
210+ const tooltipContent = `${ file . path } - ${ indicator . fullLabel } ` ;
211+
209212 return (
210- < Flex
211- align = "center"
212- gap = "1"
213- onClick = { handleClick }
214- onDoubleClick = { handleDoubleClick }
215- onContextMenu = { handleContextMenu }
216- onMouseEnter = { ( ) => setIsHovered ( true ) }
217- onMouseLeave = { ( ) => setIsHovered ( false ) }
218- className = {
219- isActive
220- ? "border-accent-8 border-y bg-accent-4"
221- : "border-transparent border-y hover:bg-gray-3"
222- }
223- style = { {
224- cursor : "pointer" ,
225- whiteSpace : "nowrap" ,
226- overflow : "hidden" ,
227- height : "26px" ,
228- paddingLeft : "8px" ,
229- paddingRight : "8px" ,
230- } }
231- >
232- < FileIcon filename = { fileName } size = { 14 } />
233- < Text
234- size = "1"
235- style = { {
236- userSelect : "none" ,
237- flexShrink : 0 ,
238- marginLeft : "2px" ,
239- } }
240- >
241- { fileName }
242- </ Text >
243- < Text
244- size = "1"
245- color = "gray"
213+ < Tooltip content = { tooltipContent } side = "top" delayDuration = { 500 } >
214+ < Flex
215+ align = "center"
216+ gap = "1"
217+ onClick = { handleClick }
218+ onDoubleClick = { handleDoubleClick }
219+ onContextMenu = { handleContextMenu }
220+ onMouseEnter = { ( ) => setIsHovered ( true ) }
221+ onMouseLeave = { ( ) => setIsHovered ( false ) }
222+ className = {
223+ isActive
224+ ? "border-accent-8 border-y bg-accent-4"
225+ : "border-transparent border-y hover:bg-gray-3"
226+ }
246227 style = { {
247- userSelect : "none" ,
228+ cursor : "pointer" ,
229+ whiteSpace : "nowrap" ,
248230 overflow : "hidden" ,
249- textOverflow : "ellipsis " ,
250- flex : 1 ,
251- marginLeft : "4px " ,
231+ height : "26px " ,
232+ paddingLeft : "8px" ,
233+ paddingRight : "8px " ,
252234 } }
253235 >
254- { file . originalPath ? `${ file . originalPath } → ${ file . path } ` : file . path }
255- </ Text >
256-
257- { hasLineStats && ! isToolbarVisible && (
258- < Flex
259- align = "center"
260- gap = "1"
261- style = { { flexShrink : 0 , fontSize : "10px" , fontFamily : "monospace" } }
236+ < FileIcon filename = { fileName } size = { 14 } />
237+ < Text
238+ size = "1"
239+ style = { {
240+ userSelect : "none" ,
241+ overflow : "hidden" ,
242+ textOverflow : "ellipsis" ,
243+ marginLeft : "2px" ,
244+ flexShrink : 1 ,
245+ minWidth : 0 ,
246+ } }
262247 >
263- { ( file . linesAdded ?? 0 ) > 0 && (
264- < Text style = { { color : "var(--green-9)" } } > +{ file . linesAdded } </ Text >
265- ) }
266- { ( file . linesRemoved ?? 0 ) > 0 && (
267- < Text style = { { color : "var(--red-9)" } } > -{ file . linesRemoved } </ Text >
268- ) }
269- </ Flex >
270- ) }
271-
272- { isToolbarVisible && (
273- < Flex align = "center" gap = "1" style = { { flexShrink : 0 } } >
274- < Tooltip content = "Discard changes" >
275- < IconButton
276- size = "1"
277- variant = "ghost"
278- color = "gray"
279- onClick = { handleDiscard }
280- style = { {
281- flexShrink : 0 ,
282- width : "18px" ,
283- height : "18px" ,
284- padding : 0 ,
285- marginLeft : "2px" ,
286- marginRight : "2px" ,
287- } }
288- >
289- < ArrowCounterClockwiseIcon size = { 12 } />
290- </ IconButton >
291- </ Tooltip >
292-
293- < DropdownMenu . Root
294- open = { isDropdownOpen }
295- onOpenChange = { setIsDropdownOpen }
248+ { fileName }
249+ </ Text >
250+ < Text
251+ size = "1"
252+ color = "gray"
253+ style = { {
254+ userSelect : "none" ,
255+ overflow : "hidden" ,
256+ textOverflow : "ellipsis" ,
257+ flex : 1 ,
258+ marginLeft : "4px" ,
259+ minWidth : 0 ,
260+ } }
261+ >
262+ { file . originalPath
263+ ? `${ file . originalPath } → ${ file . path } `
264+ : file . path }
265+ </ Text >
266+
267+ { hasLineStats && ! isToolbarVisible && (
268+ < Flex
269+ align = "center"
270+ gap = "1"
271+ style = { { flexShrink : 0 , fontSize : "10px" , fontFamily : "monospace" } }
296272 >
297- < Tooltip content = "Open file" >
298- < DropdownMenu . Trigger >
299- < IconButton
300- size = "1"
301- variant = "ghost"
302- color = "gray"
303- onClick = { ( e ) => e . stopPropagation ( ) }
304- style = { {
305- flexShrink : 0 ,
306- width : "18px" ,
307- height : "18px" ,
308- padding : 0 ,
309- } }
310- >
311- < FilePlus size = { 12 } weight = "regular" />
312- </ IconButton >
313- </ DropdownMenu . Trigger >
273+ { ( file . linesAdded ?? 0 ) > 0 && (
274+ < Text style = { { color : "var(--green-9)" } } >
275+ +{ file . linesAdded }
276+ </ Text >
277+ ) }
278+ { ( file . linesRemoved ?? 0 ) > 0 && (
279+ < Text style = { { color : "var(--red-9)" } } >
280+ -{ file . linesRemoved }
281+ </ Text >
282+ ) }
283+ </ Flex >
284+ ) }
285+
286+ { isToolbarVisible && (
287+ < Flex align = "center" gap = "1" style = { { flexShrink : 0 } } >
288+ < Tooltip content = "Discard changes" >
289+ < IconButton
290+ size = "1"
291+ variant = "ghost"
292+ color = "gray"
293+ onClick = { handleDiscard }
294+ style = { {
295+ flexShrink : 0 ,
296+ width : "18px" ,
297+ height : "18px" ,
298+ padding : 0 ,
299+ marginLeft : "2px" ,
300+ marginRight : "2px" ,
301+ } }
302+ >
303+ < ArrowCounterClockwiseIcon size = { 12 } />
304+ </ IconButton >
314305 </ Tooltip >
315- < DropdownMenu . Content size = "1" align = "end" >
316- { detectedApps
317- . filter ( ( app ) => app . type !== "terminal" )
318- . map ( ( app ) => (
319- < DropdownMenu . Item
320- key = { app . id }
321- onSelect = { ( ) => handleOpenWith ( app . id ) }
322- >
323- < Flex align = "center" gap = "2" >
324- { app . icon ? (
325- < img
326- src = { app . icon }
327- width = { 16 }
328- height = { 16 }
329- alt = ""
330- style = { { borderRadius : "2px" } }
331- />
332- ) : (
333- < CodeIcon size = { 16 } weight = "regular" />
334- ) }
335- < Text size = "1" > { app . name } </ Text >
336- </ Flex >
337- </ DropdownMenu . Item >
338- ) ) }
339- < DropdownMenu . Separator />
340- < DropdownMenu . Item onSelect = { handleCopyPath } >
341- < Flex align = "center" gap = "2" >
342- < CopyIcon size = { 16 } weight = "regular" />
343- < Text size = "1" > Copy Path</ Text >
344- </ Flex >
345- </ DropdownMenu . Item >
346- </ DropdownMenu . Content >
347- </ DropdownMenu . Root >
348- </ Flex >
349- ) }
350306
351- < Badge
352- size = "1"
353- color = { indicator . color }
354- style = { { flexShrink : 0 , fontSize : "10px" , padding : "0 4px" } }
355- >
356- { indicator . label }
357- </ Badge >
358- </ Flex >
307+ < DropdownMenu . Root
308+ open = { isDropdownOpen }
309+ onOpenChange = { setIsDropdownOpen }
310+ >
311+ < Tooltip content = "Open file" >
312+ < DropdownMenu . Trigger >
313+ < IconButton
314+ size = "1"
315+ variant = "ghost"
316+ color = "gray"
317+ onClick = { ( e ) => e . stopPropagation ( ) }
318+ style = { {
319+ flexShrink : 0 ,
320+ width : "18px" ,
321+ height : "18px" ,
322+ padding : 0 ,
323+ } }
324+ >
325+ < FilePlus size = { 12 } weight = "regular" />
326+ </ IconButton >
327+ </ DropdownMenu . Trigger >
328+ </ Tooltip >
329+ < DropdownMenu . Content size = "1" align = "end" >
330+ { detectedApps
331+ . filter ( ( app ) => app . type !== "terminal" )
332+ . map ( ( app ) => (
333+ < DropdownMenu . Item
334+ key = { app . id }
335+ onSelect = { ( ) => handleOpenWith ( app . id ) }
336+ >
337+ < Flex align = "center" gap = "2" >
338+ { app . icon ? (
339+ < img
340+ src = { app . icon }
341+ width = { 16 }
342+ height = { 16 }
343+ alt = ""
344+ style = { { borderRadius : "2px" } }
345+ />
346+ ) : (
347+ < CodeIcon size = { 16 } weight = "regular" />
348+ ) }
349+ < Text size = "1" > { app . name } </ Text >
350+ </ Flex >
351+ </ DropdownMenu . Item >
352+ ) ) }
353+ < DropdownMenu . Separator />
354+ < DropdownMenu . Item onSelect = { handleCopyPath } >
355+ < Flex align = "center" gap = "2" >
356+ < CopyIcon size = { 16 } weight = "regular" />
357+ < Text size = "1" > Copy Path</ Text >
358+ </ Flex >
359+ </ DropdownMenu . Item >
360+ </ DropdownMenu . Content >
361+ </ DropdownMenu . Root >
362+ </ Flex >
363+ ) }
364+
365+ < Badge
366+ size = "1"
367+ color = { indicator . color }
368+ style = { { flexShrink : 0 , fontSize : "10px" , padding : "0 4px" } }
369+ >
370+ { indicator . label }
371+ </ Badge >
372+ </ Flex >
373+ </ Tooltip >
359374 ) ;
360375}
361376
0 commit comments