@@ -12,9 +12,18 @@ import {
1212 Badge ,
1313 Separator ,
1414 StandardTooltip ,
15+ AlertDialog ,
16+ AlertDialogContent ,
17+ AlertDialogHeader ,
18+ AlertDialogTitle ,
19+ AlertDialogDescription ,
20+ AlertDialogFooter ,
21+ AlertDialogCancel ,
22+ AlertDialogAction ,
1523} from "@src/components/ui"
1624import { cn } from "@/lib/utils"
1725import type { ModeConfig } from "@roo-code/types"
26+ import { useAppTranslation } from "@src/i18n/TranslationContext"
1827
1928const SOURCE_INFO = {
2029 builtin : {
@@ -51,6 +60,11 @@ interface ModeEnableDisableDialogProps {
5160 onSave : ( updatedModes : ModeWithSource [ ] ) => void
5261}
5362
63+ interface DeleteState {
64+ open : boolean
65+ tMode ?: { slug : string ; name : string ; source ?: string ; rulesFolderPath ?: string } | null
66+ }
67+
5468interface GroupedModes {
5569 builtin : ModeWithSource [ ]
5670 global : ModeWithSource [ ]
@@ -87,6 +101,10 @@ export const ModeEnableDisableDialog: React.FC<ModeEnableDisableDialogProps> = (
87101 const [ localModes , setLocalModes ] = useState < ModeWithSource [ ] > ( modes )
88102 const [ hasChanges , setHasChanges ] = useState ( false )
89103
104+ const { t } = useAppTranslation ( )
105+
106+ const [ deleteState , setDeleteState ] = useState < DeleteState > ( { open : false , tMode : null } )
107+
90108 // Update local state when props change
91109 useEffect ( ( ) => {
92110 setLocalModes ( modes )
@@ -184,10 +202,55 @@ export const ModeEnableDisableDialog: React.FC<ModeEnableDisableDialogProps> = (
184202 </ div >
185203 < div className = "status-indicator flex items-center gap-1 flex-shrink-0" >
186204 { mode . disabled ? < EyeOff className = "size-4 disabled" /> : < Eye className = "size-4 enabled" /> }
205+ { /* Show delete for global custom modes (they override built-in or are user-created) */ }
206+ { mode . source === "global" && (
207+ < Button
208+ variant = "ghost"
209+ size = "icon"
210+ onClick = { ( ) => {
211+ // Ask the extension to check for rules folder and return path via message
212+ setDeleteState ( {
213+ open : false ,
214+ tMode : { slug : mode . slug , name : mode . name , source : mode . source } ,
215+ } )
216+ // Request checkOnly first
217+ window . parent . postMessage (
218+ { type : "deleteCustomMode" , slug : mode . slug , checkOnly : true } ,
219+ "*" ,
220+ )
221+ } } >
222+ < span className = "codicon codicon-trash" > </ span >
223+ </ Button >
224+ ) }
187225 </ div >
188226 </ div >
189227 )
190228
229+ // Listen for delete check responses from extension
230+ useEffect ( ( ) => {
231+ const handler = ( e : MessageEvent ) => {
232+ const message = e . data
233+ if ( message . type === "deleteCustomModeCheck" ) {
234+ if ( message . slug && deleteState . tMode && deleteState . tMode . slug === message . slug ) {
235+ setDeleteState ( {
236+ open : true ,
237+ tMode : { ...deleteState . tMode , rulesFolderPath : message . rulesFolderPath } ,
238+ } )
239+ }
240+ }
241+ }
242+ window . addEventListener ( "message" , handler )
243+ return ( ) => window . removeEventListener ( "message" , handler )
244+ } , [ deleteState . tMode ] )
245+
246+ const confirmDelete = ( ) => {
247+ if ( ! deleteState . tMode ) return
248+ window . parent . postMessage ( { type : "deleteCustomMode" , slug : deleteState . tMode . slug } , "*" )
249+ setDeleteState ( { open : false , tMode : null } )
250+ // Close dialog after request; backend will refresh state
251+ onOpenChange ( false )
252+ }
253+
191254 // Source group component
192255 const SourceGroup : React . FC < { source : ModeSource ; modes : ModeWithSource [ ] } > = ( { source, modes } ) => {
193256 const sourceInfo = SOURCE_INFO [ source ]
@@ -317,6 +380,39 @@ export const ModeEnableDisableDialog: React.FC<ModeEnableDisableDialogProps> = (
317380 </ Button >
318381 </ div >
319382 </ DialogFooter >
383+
384+ { /* Delete confirmation dialog for global custom modes */ }
385+ < AlertDialog open = { ! ! deleteState . open } onOpenChange = { ( open ) => setDeleteState ( ( s ) => ( { ...s , open } ) ) } >
386+ < AlertDialogContent >
387+ < AlertDialogHeader >
388+ < AlertDialogTitle > { t ? t ( "prompts:deleteMode.title" ) : "Delete mode" } </ AlertDialogTitle >
389+ < AlertDialogDescription >
390+ { deleteState . tMode && (
391+ < >
392+ { t
393+ ? t ( "prompts:deleteMode.message" , { modeName : deleteState . tMode . name } )
394+ : `Delete ${ deleteState . tMode . name } ?` }
395+ { deleteState . tMode . rulesFolderPath && (
396+ < div className = "mt-2" >
397+ { t
398+ ? t ( "prompts:deleteMode.rulesFolder" , {
399+ folderPath : deleteState . tMode . rulesFolderPath ,
400+ } )
401+ : deleteState . tMode . rulesFolderPath }
402+ </ div >
403+ ) }
404+ </ >
405+ ) }
406+ </ AlertDialogDescription >
407+ </ AlertDialogHeader >
408+ < AlertDialogFooter >
409+ < AlertDialogCancel > { t ? t ( "prompts:deleteMode.cancel" ) : "Cancel" } </ AlertDialogCancel >
410+ < AlertDialogAction onClick = { confirmDelete } >
411+ { t ? t ( "prompts:deleteMode.confirm" ) : "Delete" }
412+ </ AlertDialogAction >
413+ </ AlertDialogFooter >
414+ </ AlertDialogContent >
415+ </ AlertDialog >
320416 </ DialogContent >
321417 </ Dialog >
322418 )
0 commit comments