@@ -9,6 +9,12 @@ import { ModelDisplay } from "./Messages/ModelDisplay";
99import { StatusIndicator } from "./StatusIndicator" ;
1010import { useRename } from "@/contexts/WorkspaceRenameContext" ;
1111import { cn } from "@/lib/utils" ;
12+ import {
13+ ContextMenu ,
14+ ContextMenuContent ,
15+ ContextMenuItem ,
16+ ContextMenuTrigger ,
17+ } from "@/components/ui/context-menu" ;
1218
1319export interface WorkspaceSelection {
1420 projectPath : string ;
@@ -130,89 +136,112 @@ const WorkspaceListItemInner: React.FC<WorkspaceListItemProps> = ({
130136
131137 return (
132138 < React . Fragment >
133- < div
134- className = { cn (
135- "py-1.5 px-3 pl-7 cursor-pointer grid grid-cols-[auto_auto_1fr_auto] gap-2 items-center border-l-[3px] border-transparent transition-all duration-150 text-[13px] relative hover:bg-bg-hover [&:hover_button]:opacity-100" ,
136- isSelected && "bg-bg-hover border-l-[#569cd6]"
137- ) }
138- onClick = { ( ) =>
139- onSelectWorkspace ( {
140- projectPath,
141- projectName,
142- namedWorkspacePath,
143- workspaceId,
144- } )
145- }
146- onKeyDown = { ( e ) => {
147- if ( e . key === "Enter" || e . key === " " ) {
148- e . preventDefault ( ) ;
149- onSelectWorkspace ( {
150- projectPath,
151- projectName,
152- namedWorkspacePath,
153- workspaceId,
154- } ) ;
155- }
156- } }
157- role = "button"
158- tabIndex = { 0 }
159- aria-current = { isSelected ? "true" : undefined }
160- data-workspace-path = { namedWorkspacePath }
161- data-workspace-id = { workspaceId }
162- >
163- < TooltipWrapper inline >
164- < button
165- className = "opacity-0 bg-transparent text-muted border-none cursor-pointer text-base p-0 w-5 h-5 flex items-center justify-center transition-all duration-200 flex-shrink-0 col-start-1 hover:text-foreground hover:bg-white/10 hover:rounded-sm"
166- onClick = { ( e ) => {
167- e . stopPropagation ( ) ;
168- void onRemoveWorkspace ( workspaceId , e . currentTarget ) ;
139+ < ContextMenu >
140+ < ContextMenuTrigger asChild >
141+ < div
142+ className = { cn (
143+ "py-1.5 px-3 pl-7 cursor-pointer grid grid-cols-[auto_auto_1fr_auto] gap-2 items-center border-l-[3px] border-transparent transition-all duration-150 text-[13px] relative hover:bg-bg-hover [&:hover_button]:opacity-100" ,
144+ isSelected && "bg-bg-hover border-l-[#569cd6]"
145+ ) }
146+ onClick = { ( ) =>
147+ onSelectWorkspace ( {
148+ projectPath,
149+ projectName,
150+ namedWorkspacePath,
151+ workspaceId,
152+ } )
153+ }
154+ onKeyDown = { ( e ) => {
155+ if ( e . key === "Enter" || e . key === " " ) {
156+ e . preventDefault ( ) ;
157+ onSelectWorkspace ( {
158+ projectPath,
159+ projectName,
160+ namedWorkspacePath,
161+ workspaceId,
162+ } ) ;
163+ }
169164 } }
170- aria-label = { `Remove workspace ${ displayName } ` }
165+ role = "button"
166+ tabIndex = { 0 }
167+ aria-current = { isSelected ? "true" : undefined }
168+ data-workspace-path = { namedWorkspacePath }
171169 data-workspace-id = { workspaceId }
172170 >
173- ×
174- </ button >
175- < Tooltip className = "tooltip" align = "right" >
176- Remove workspace
177- </ Tooltip >
178- </ TooltipWrapper >
179- < GitStatusIndicator
180- gitStatus = { gitStatus }
181- workspaceId = { workspaceId }
182- tooltipPosition = "right"
183- />
184- { isEditing ? (
185- < input
186- className = "bg-input-bg text-input-text border border-input-border rounded-sm px-1 py-0.5 text-[13px] font-inherit outline-none min-w-0 text-right focus:border-input-border-focus"
187- value = { editingName }
188- onChange = { ( e ) => setEditingName ( e . target . value ) }
189- onKeyDown = { handleRenameKeyDown }
190- onBlur = { ( ) => void handleConfirmRename ( ) }
191- autoFocus
192- onClick = { ( e ) => e . stopPropagation ( ) }
193- aria-label = { `Rename workspace ${ displayName } ` }
194- data-workspace-id = { workspaceId }
195- />
196- ) : (
197- < span
198- className = "text-foreground text-[14px] whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer px-1 py-0.5 rounded-sm transition-colors duration-200 min-w-0 text-right hover:bg-white/5"
199- onDoubleClick = { ( e ) => {
171+ < TooltipWrapper inline >
172+ < button
173+ className = "opacity-0 bg-transparent text-muted border-none cursor-pointer text-base p-0 w-5 h-5 flex items-center justify-center transition-all duration-200 flex-shrink-0 col-start-1 hover:text-foreground hover:bg-white/10 hover:rounded-sm"
174+ onClick = { ( e ) => {
175+ e . stopPropagation ( ) ;
176+ void onRemoveWorkspace ( workspaceId , e . currentTarget ) ;
177+ } }
178+ aria-label = { `Remove workspace ${ displayName } ` }
179+ data-workspace-id = { workspaceId }
180+ >
181+ ×
182+ </ button >
183+ < Tooltip className = "tooltip" align = "right" >
184+ Remove workspace
185+ </ Tooltip >
186+ </ TooltipWrapper >
187+ < GitStatusIndicator
188+ gitStatus = { gitStatus }
189+ workspaceId = { workspaceId }
190+ tooltipPosition = "right"
191+ />
192+ { isEditing ? (
193+ < input
194+ className = "bg-input-bg text-input-text border border-input-border rounded-sm px-1 py-0.5 text-[13px] font-inherit outline-none min-w-0 text-right focus:border-input-border-focus"
195+ value = { editingName }
196+ onChange = { ( e ) => setEditingName ( e . target . value ) }
197+ onKeyDown = { handleRenameKeyDown }
198+ onBlur = { ( ) => void handleConfirmRename ( ) }
199+ autoFocus
200+ onClick = { ( e ) => e . stopPropagation ( ) }
201+ aria-label = { `Rename workspace ${ displayName } ` }
202+ data-workspace-id = { workspaceId }
203+ />
204+ ) : (
205+ < span
206+ className = "text-foreground text-[14px] whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer px-1 py-0.5 rounded-sm transition-colors duration-200 min-w-0 text-right hover:bg-white/5"
207+ onDoubleClick = { ( e ) => {
208+ e . stopPropagation ( ) ;
209+ startRenaming ( ) ;
210+ } }
211+ title = "Double-click to rename"
212+ >
213+ { displayName }
214+ </ span >
215+ ) }
216+ < StatusIndicator
217+ className = "ml-2"
218+ streaming = { isStreaming }
219+ unread = { isUnread }
220+ onClick = { handleToggleUnread }
221+ title = { statusTooltipTitle }
222+ />
223+ </ div >
224+ </ ContextMenuTrigger >
225+ < ContextMenuContent >
226+ < ContextMenuItem
227+ onClick = { ( e ) => {
200228 e . stopPropagation ( ) ;
201229 startRenaming ( ) ;
202230 } }
203- title = "Double-click to rename"
204231 >
205- { displayName }
206- </ span >
207- ) }
208- < StatusIndicator
209- className = "ml-2"
210- streaming = { isStreaming }
211- unread = { isUnread }
212- onClick = { handleToggleUnread }
213- title = { statusTooltipTitle }
214- />
215- </ div >
232+ Rename
233+ </ ContextMenuItem >
234+ < ContextMenuItem
235+ onClick = { ( e ) => {
236+ e . stopPropagation ( ) ;
237+ void onRemoveWorkspace ( workspaceId , e . currentTarget as HTMLElement ) ;
238+ } }
239+ className = "text-error focus:text-error"
240+ >
241+ Remove
242+ </ ContextMenuItem >
243+ </ ContextMenuContent >
244+ </ ContextMenu >
216245 { renameError && isEditing && (
217246 < div className = "absolute top-full left-7 right-8 mt-1 px-2 py-1.5 bg-error-bg border border-error rounded-sm text-error text-xs z-10" >
218247 { renameError }
0 commit comments