1
1
import React from "react"
2
- import { ListChecks , LayoutList , Settings , CheckCheck } from "lucide-react"
2
+ import { ListChecks , LayoutList , Settings , CheckCheck , X } from "lucide-react"
3
3
4
4
import { vscode } from "@/utils/vscode"
5
5
import { cn } from "@/lib/utils"
6
6
import { useExtensionState } from "@/context/ExtensionStateContext"
7
7
import { useAppTranslation } from "@/i18n/TranslationContext"
8
8
import { useRooPortal } from "@/components/ui/hooks/useRooPortal"
9
- import { Popover , PopoverContent , PopoverTrigger , StandardTooltip } from "@/components/ui"
9
+ import { Popover , PopoverContent , PopoverTrigger , StandardTooltip , ToggleSwitch } from "@/components/ui"
10
10
import { AutoApproveSetting , autoApproveSettingsConfig } from "../settings/AutoApproveToggle"
11
11
import { useAutoApprovalToggles } from "@/hooks/useAutoApprovalToggles"
12
+ import { useAutoApprovalState } from "@/hooks/useAutoApprovalState"
12
13
13
14
interface AutoApproveDropdownProps {
14
15
disabled ?: boolean
@@ -124,20 +125,24 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }:
124
125
Object . keys ( autoApproveSettingsConfig ) . forEach ( ( key ) => {
125
126
onAutoApproveToggle ( key as AutoApproveSetting , false )
126
127
} )
127
- // Disable master auto-approval
128
- if ( autoApprovalEnabled ) {
129
- setAutoApprovalEnabled ( false )
130
- vscode . postMessage ( { type : "autoApprovalEnabled" , bool : false } )
131
- }
132
- } , [ onAutoApproveToggle , autoApprovalEnabled , setAutoApprovalEnabled ] )
128
+ } , [ onAutoApproveToggle ] )
133
129
134
130
const handleOpenSettings = React . useCallback (
135
131
( ) =>
136
132
window . postMessage ( { type : "action" , action : "settingsButtonClicked" , values : { section : "autoApprove" } } ) ,
137
133
[ ] ,
138
134
)
139
135
136
+ // Handle the main auto-approval toggle
137
+ const handleAutoApprovalToggle = React . useCallback ( ( ) => {
138
+ const newValue = ! ( autoApprovalEnabled ?? false )
139
+ setAutoApprovalEnabled ( newValue )
140
+ vscode . postMessage ( { type : "autoApprovalEnabled" , bool : newValue } )
141
+ } , [ autoApprovalEnabled , setAutoApprovalEnabled ] )
142
+
140
143
// Calculate enabled and total counts as separate properties
144
+ const settingsArray = Object . values ( autoApproveSettingsConfig )
145
+
141
146
const enabledCount = React . useMemo ( ( ) => {
142
147
return Object . values ( toggles ) . filter ( ( value ) => ! ! value ) . length
143
148
} , [ toggles ] )
@@ -146,11 +151,7 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }:
146
151
return Object . keys ( toggles ) . length
147
152
} , [ toggles ] )
148
153
149
- // Split settings into two columns
150
- const settingsArray = Object . values ( autoApproveSettingsConfig )
151
- const halfLength = Math . ceil ( settingsArray . length / 2 )
152
- const firstColumn = settingsArray . slice ( 0 , halfLength )
153
- const secondColumn = settingsArray . slice ( halfLength )
154
+ const { effectiveAutoApprovalEnabled } = useAutoApprovalState ( toggles , autoApprovalEnabled )
154
155
155
156
return (
156
157
< Popover open = { open } onOpenChange = { setOpen } data-testid = "auto-approve-dropdown-root" >
@@ -167,19 +168,26 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }:
167
168
: "opacity-90 hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)] cursor-pointer" ,
168
169
triggerClassName ,
169
170
) } >
170
- < CheckCheck className = "size-3 flex-shrink-0" />
171
+ { ! effectiveAutoApprovalEnabled ? (
172
+ < X className = "size-3 flex-shrink-0" />
173
+ ) : (
174
+ < CheckCheck className = "size-3 flex-shrink-0" />
175
+ ) }
176
+
171
177
< span className = "truncate min-w-0" >
172
- { enabledCount === totalCount
173
- ? t ( "chat:autoApprove.triggerLabelAll" )
174
- : t ( "chat:autoApprove.triggerLabel" , { count : enabledCount } ) }
178
+ { ! effectiveAutoApprovalEnabled
179
+ ? t ( "chat:autoApprove.triggerLabelOff" )
180
+ : enabledCount === totalCount
181
+ ? t ( "chat:autoApprove.triggerLabelAll" )
182
+ : t ( "chat:autoApprove.triggerLabel" , { count : enabledCount } ) }
175
183
</ span >
176
184
</ PopoverTrigger >
177
185
</ StandardTooltip >
178
186
< PopoverContent
179
187
align = "start"
180
188
sideOffset = { 4 }
181
189
container = { portalContainer }
182
- className = "p-0 overflow-hidden min-w-96 max-w-9/10"
190
+ className = "p-0 overflow-hidden min-w-90 max-w-9/10"
183
191
onOpenAutoFocus = { ( e ) => e . preventDefault ( ) } >
184
192
< div className = "flex flex-col w-full" >
185
193
{ /* Header with description */ }
@@ -197,66 +205,32 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }:
197
205
{ t ( "chat:autoApprove.description" ) }
198
206
</ p >
199
207
</ div >
200
-
201
- { /* Two-column layout for approval options */ }
202
- < div className = "p-3" >
203
- < div className = "grid grid-cols-2 gap-x-4 gap-y-2" >
204
- { /* First Column */ }
205
- < div className = "space-y-2" >
206
- { firstColumn . map ( ( { key, labelKey, descriptionKey, icon } ) => {
207
- const isEnabled = toggles [ key ]
208
- return (
209
- < StandardTooltip key = { key } content = { t ( descriptionKey ) } >
210
- < button
211
- onClick = { ( ) => onAutoApproveToggle ( key , ! isEnabled ) }
212
- className = { cn (
213
- "w-full flex items-center gap-2 px-2 py-1.5 rounded text-xs text-left" ,
214
- "transition-all duration-150" ,
215
- "hover:bg-vscode-list-hoverBackground" ,
216
- isEnabled
217
- ? "bg-vscode-button-background text-vscode-button-foreground"
218
- : "bg-transparent text-vscode-foreground opacity-70 hover:opacity-100" ,
219
- ) }
220
- data-testid = { `auto-approve-${ key } ` } >
221
- < span className = { `codicon codicon-${ icon } text-sm flex-shrink-0` } />
222
- < span className = "flex-1 truncate" > { t ( labelKey ) } </ span >
223
- { isEnabled && (
224
- < span className = "codicon codicon-check text-xs flex-shrink-0" />
225
- ) }
226
- </ button >
227
- </ StandardTooltip >
228
- )
229
- } ) }
230
- </ div >
231
-
232
- { /* Second Column */ }
233
- < div className = "space-y-2" >
234
- { secondColumn . map ( ( { key, labelKey, descriptionKey, icon } ) => {
235
- const isEnabled = toggles [ key ]
236
- return (
237
- < StandardTooltip key = { key } content = { t ( descriptionKey ) } >
238
- < button
239
- onClick = { ( ) => onAutoApproveToggle ( key , ! isEnabled ) }
240
- className = { cn (
241
- "w-full flex items-center gap-2 px-2 py-1.5 rounded text-xs text-left" ,
242
- "transition-all duration-150" ,
243
- "hover:bg-vscode-list-hoverBackground" ,
244
- isEnabled
245
- ? "bg-vscode-button-background text-vscode-button-foreground"
246
- : "bg-transparent text-vscode-foreground opacity-70 hover:opacity-100" ,
247
- ) }
248
- data-testid = { `auto-approve-${ key } ` } >
249
- < span className = { `codicon codicon-${ icon } text-sm flex-shrink-0` } />
250
- < span className = "flex-1 truncate" > { t ( labelKey ) } </ span >
251
- { isEnabled && (
252
- < span className = "codicon codicon-check text-xs flex-shrink-0" />
253
- ) }
254
- </ button >
255
- </ StandardTooltip >
256
- )
257
- } ) }
258
- </ div >
259
- </ div >
208
+ < div className = "grid grid-cols-2 gap-x-2 gap-y-2 p-3" >
209
+ { settingsArray . map ( ( { key, labelKey, descriptionKey, icon } ) => {
210
+ const isEnabled = toggles [ key ]
211
+ return (
212
+ < StandardTooltip key = { key } content = { t ( descriptionKey ) } >
213
+ < button
214
+ onClick = { ( ) => onAutoApproveToggle ( key , ! isEnabled ) }
215
+ className = { cn (
216
+ "flex items-center gap-2 px-2 py-2 rounded text-sm text-left" ,
217
+ "transition-all duration-150" ,
218
+ "opacity-100 hover:opacity-70" ,
219
+ "cursor-pointer" ,
220
+ ! effectiveAutoApprovalEnabled &&
221
+ "opacity-50 cursor-not-allowed hover:opacity-50" ,
222
+ isEnabled
223
+ ? "bg-vscode-button-background text-vscode-button-foreground"
224
+ : "bg-vscode-button-background/15 text-vscode-foreground hover:bg-vscode-list-hoverBackground" ,
225
+ ) }
226
+ disabled = { ! effectiveAutoApprovalEnabled }
227
+ data-testid = { `auto-approve-${ key } ` } >
228
+ < span className = { `codicon codicon-${ icon } text-sm flex-shrink-0` } />
229
+ < span className = "flex-1 truncate" > { t ( labelKey ) } </ span >
230
+ </ button >
231
+ </ StandardTooltip >
232
+ )
233
+ } ) }
260
234
</ div >
261
235
262
236
{ /* Bottom bar with Select All/None buttons */ }
@@ -265,6 +239,7 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }:
265
239
< button
266
240
aria-label = { t ( "chat:autoApprove.selectAll" ) }
267
241
onClick = { handleSelectAll }
242
+ disabled = { ! effectiveAutoApprovalEnabled }
268
243
className = { cn (
269
244
"relative inline-flex items-center justify-center gap-1" ,
270
245
"bg-transparent border-none px-2 py-1" ,
@@ -275,13 +250,15 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }:
275
250
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder" ,
276
251
"active:bg-[rgba(255,255,255,0.1)]" ,
277
252
"cursor-pointer" ,
253
+ ! effectiveAutoApprovalEnabled && "opacity-50 hover:opacity-50 cursor-not-allowed" ,
278
254
) } >
279
255
< ListChecks className = "w-3.5 h-3.5" />
280
256
< span > { t ( "chat:autoApprove.all" ) } </ span >
281
257
</ button >
282
258
< button
283
259
aria-label = { t ( "chat:autoApprove.selectNone" ) }
284
260
onClick = { handleSelectNone }
261
+ disabled = { ! effectiveAutoApprovalEnabled }
285
262
className = { cn (
286
263
"relative inline-flex items-center justify-center gap-1" ,
287
264
"bg-transparent border-none px-2 py-1" ,
@@ -292,11 +269,30 @@ export const AutoApproveDropdown = ({ disabled = false, triggerClassName = "" }:
292
269
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder" ,
293
270
"active:bg-[rgba(255,255,255,0.1)]" ,
294
271
"cursor-pointer" ,
272
+ ! effectiveAutoApprovalEnabled && "opacity-50 hover:opacity-50 cursor-not-allowed" ,
295
273
) } >
296
274
< LayoutList className = "w-3.5 h-3.5" />
297
275
< span > { t ( "chat:autoApprove.none" ) } </ span >
298
276
</ button >
299
277
</ div >
278
+
279
+ < label
280
+ className = "flex items-center gap-2 pr-2 cursor-pointer"
281
+ onClick = { ( e ) => {
282
+ // Prevent label click when clicking on the toggle switch itself
283
+ if ( ( e . target as HTMLElement ) . closest ( '[role="switch"]' ) ) {
284
+ e . preventDefault ( )
285
+ return
286
+ }
287
+ handleAutoApprovalToggle ( )
288
+ } } >
289
+ < ToggleSwitch
290
+ checked = { effectiveAutoApprovalEnabled }
291
+ aria-label = "Toggle auto-approval"
292
+ onChange = { handleAutoApprovalToggle }
293
+ />
294
+ < span className = { cn ( "text-sm font-bold select-none" ) } > Enabled</ span >
295
+ </ label >
300
296
</ div >
301
297
</ div >
302
298
</ PopoverContent >
0 commit comments