1- import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
2- import { useCallback , useState } from "react"
1+ import { useCallback , useMemo , useState } from "react"
32import { Trans } from "react-i18next"
4- import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
5-
6- import { Button } from "@/components/ui"
3+ import { VSCodeCheckbox , VSCodeLink } from "@vscode/webview-ui-toolkit/react"
74
85import { vscode } from "../../utils/vscode"
96import { useExtensionState } from "../../context/ExtensionStateContext"
107import { useAppTranslation } from "../../i18n/TranslationContext"
11-
12- const ICON_MAP : Record < string , string > = {
13- readFiles : "eye" ,
14- editFiles : "edit" ,
15- executeCommands : "terminal" ,
16- useBrowser : "globe" ,
17- useMcp : "plug" ,
18- switchModes : "sync" ,
19- subtasks : "discard" ,
20- retryRequests : "refresh" ,
21- }
22-
23- interface AutoApproveAction {
24- id : string
25- label : string
26- enabled : boolean
27- description : string
28- }
8+ import { AutoApproveToggle , AutoApproveSetting , autoApproveSettingsConfig } from "../settings/AutoApproveToggle"
299
3010interface AutoApproveMenuProps {
3111 style ?: React . CSSProperties
3212}
3313
3414const AutoApproveMenu = ( { style } : AutoApproveMenuProps ) => {
3515 const [ isExpanded , setIsExpanded ] = useState ( false )
16+
3617 const {
18+ autoApprovalEnabled,
19+ setAutoApprovalEnabled,
3720 alwaysAllowReadOnly,
38- setAlwaysAllowReadOnly,
3921 alwaysAllowWrite,
40- setAlwaysAllowWrite,
4122 alwaysAllowExecute,
42- setAlwaysAllowExecute,
4323 alwaysAllowBrowser,
44- setAlwaysAllowBrowser,
4524 alwaysAllowMcp,
46- setAlwaysAllowMcp,
4725 alwaysAllowModeSwitch,
48- setAlwaysAllowModeSwitch,
4926 alwaysAllowSubtasks,
50- setAlwaysAllowSubtasks,
5127 alwaysApproveResubmit,
28+ setAlwaysAllowReadOnly,
29+ setAlwaysAllowWrite,
30+ setAlwaysAllowExecute,
31+ setAlwaysAllowBrowser,
32+ setAlwaysAllowMcp,
33+ setAlwaysAllowModeSwitch,
34+ setAlwaysAllowSubtasks,
5235 setAlwaysApproveResubmit,
53- autoApprovalEnabled,
54- setAutoApprovalEnabled,
5536 } = useExtensionState ( )
5637
5738 const { t } = useAppTranslation ( )
5839
59- const actions : AutoApproveAction [ ] = [
60- {
61- id : "readFiles" ,
62- label : t ( "chat:autoApprove.actions.readFiles.label" ) ,
63- enabled : alwaysAllowReadOnly ?? false ,
64- description : t ( "chat:autoApprove.actions.readFiles.description" ) ,
65- } ,
66- {
67- id : "editFiles" ,
68- label : t ( "chat:autoApprove.actions.editFiles.label" ) ,
69- enabled : alwaysAllowWrite ?? false ,
70- description : t ( "chat:autoApprove.actions.editFiles.description" ) ,
71- } ,
72- {
73- id : "executeCommands" ,
74- label : t ( "chat:autoApprove.actions.executeCommands.label" ) ,
75- enabled : alwaysAllowExecute ?? false ,
76- description : t ( "chat:autoApprove.actions.executeCommands.description" ) ,
77- } ,
78- {
79- id : "useBrowser" ,
80- label : t ( "chat:autoApprove.actions.useBrowser.label" ) ,
81- enabled : alwaysAllowBrowser ?? false ,
82- description : t ( "chat:autoApprove.actions.useBrowser.description" ) ,
83- } ,
84- {
85- id : "useMcp" ,
86- label : t ( "chat:autoApprove.actions.useMcp.label" ) ,
87- enabled : alwaysAllowMcp ?? false ,
88- description : t ( "chat:autoApprove.actions.useMcp.description" ) ,
89- } ,
90- {
91- id : "switchModes" ,
92- label : t ( "chat:autoApprove.actions.switchModes.label" ) ,
93- enabled : alwaysAllowModeSwitch ?? false ,
94- description : t ( "chat:autoApprove.actions.switchModes.description" ) ,
40+ const onAutoApproveToggle = useCallback (
41+ ( key : AutoApproveSetting , value : boolean ) => {
42+ vscode . postMessage ( { type : key , bool : value } )
43+
44+ switch ( key ) {
45+ case "alwaysAllowReadOnly" :
46+ setAlwaysAllowReadOnly ( value )
47+ break
48+ case "alwaysAllowWrite" :
49+ setAlwaysAllowWrite ( value )
50+ break
51+ case "alwaysAllowExecute" :
52+ setAlwaysAllowExecute ( value )
53+ break
54+ case "alwaysAllowBrowser" :
55+ setAlwaysAllowBrowser ( value )
56+ break
57+ case "alwaysAllowMcp" :
58+ setAlwaysAllowMcp ( value )
59+ break
60+ case "alwaysAllowModeSwitch" :
61+ setAlwaysAllowModeSwitch ( value )
62+ break
63+ case "alwaysAllowSubtasks" :
64+ setAlwaysAllowSubtasks ( value )
65+ break
66+ case "alwaysApproveResubmit" :
67+ setAlwaysApproveResubmit ( value )
68+ break
69+ }
9570 } ,
96- {
97- id : "subtasks" ,
98- label : t ( "chat:autoApprove.actions.subtasks.label" ) ,
99- enabled : alwaysAllowSubtasks ?? false ,
100- description : t ( "chat:autoApprove.actions.subtasks.description" ) ,
101- } ,
102- {
103- id : "retryRequests" ,
104- label : t ( "chat:autoApprove.actions.retryRequests.label" ) ,
105- enabled : alwaysApproveResubmit ?? false ,
106- description : t ( "chat:autoApprove.actions.retryRequests.description" ) ,
107- } ,
108- ]
71+ [
72+ setAlwaysAllowReadOnly ,
73+ setAlwaysAllowWrite ,
74+ setAlwaysAllowExecute ,
75+ setAlwaysAllowBrowser ,
76+ setAlwaysAllowMcp ,
77+ setAlwaysAllowModeSwitch ,
78+ setAlwaysAllowSubtasks ,
79+ setAlwaysApproveResubmit ,
80+ ] ,
81+ )
10982
110- const toggleExpanded = useCallback ( ( ) => {
111- setIsExpanded ( ( prev ) => ! prev )
112- } , [ ] )
83+ const toggleExpanded = useCallback ( ( ) => setIsExpanded ( ( prev ) => ! prev ) , [ ] )
84+
85+ const toggles = useMemo (
86+ ( ) => ( {
87+ alwaysAllowReadOnly : alwaysAllowReadOnly ,
88+ alwaysAllowWrite : alwaysAllowWrite ,
89+ alwaysAllowExecute : alwaysAllowExecute ,
90+ alwaysAllowBrowser : alwaysAllowBrowser ,
91+ alwaysAllowMcp : alwaysAllowMcp ,
92+ alwaysAllowModeSwitch : alwaysAllowModeSwitch ,
93+ alwaysAllowSubtasks : alwaysAllowSubtasks ,
94+ alwaysApproveResubmit : alwaysApproveResubmit ,
95+ } ) ,
96+ [
97+ alwaysAllowReadOnly ,
98+ alwaysAllowWrite ,
99+ alwaysAllowExecute ,
100+ alwaysAllowBrowser ,
101+ alwaysAllowMcp ,
102+ alwaysAllowModeSwitch ,
103+ alwaysAllowSubtasks ,
104+ alwaysApproveResubmit ,
105+ ] ,
106+ )
113107
114- const enabledActionsList = actions
115- . filter ( ( action ) => action . enabled )
116- . map ( ( action ) => action . label )
108+ const enabledActionsList = Object . entries ( toggles )
109+ . filter ( ( [ _key , value ] ) => ! ! value )
110+ . map ( ( [ key ] ) => t ( autoApproveSettingsConfig [ key as AutoApproveSetting ] . labelKey ) )
117111 . join ( ", " )
118112
119- // Individual checkbox handlers - each one only updates its own state.
120- const handleReadOnlyChange = useCallback ( ( ) => {
121- const newValue = ! ( alwaysAllowReadOnly ?? false )
122- setAlwaysAllowReadOnly ( newValue )
123- vscode . postMessage ( { type : "alwaysAllowReadOnly" , bool : newValue } )
124- } , [ alwaysAllowReadOnly , setAlwaysAllowReadOnly ] )
125-
126- const handleWriteChange = useCallback ( ( ) => {
127- const newValue = ! ( alwaysAllowWrite ?? false )
128- setAlwaysAllowWrite ( newValue )
129- vscode . postMessage ( { type : "alwaysAllowWrite" , bool : newValue } )
130- } , [ alwaysAllowWrite , setAlwaysAllowWrite ] )
131-
132- const handleExecuteChange = useCallback ( ( ) => {
133- const newValue = ! ( alwaysAllowExecute ?? false )
134- setAlwaysAllowExecute ( newValue )
135- vscode . postMessage ( { type : "alwaysAllowExecute" , bool : newValue } )
136- } , [ alwaysAllowExecute , setAlwaysAllowExecute ] )
137-
138- const handleBrowserChange = useCallback ( ( ) => {
139- const newValue = ! ( alwaysAllowBrowser ?? false )
140- setAlwaysAllowBrowser ( newValue )
141- vscode . postMessage ( { type : "alwaysAllowBrowser" , bool : newValue } )
142- } , [ alwaysAllowBrowser , setAlwaysAllowBrowser ] )
143-
144- const handleMcpChange = useCallback ( ( ) => {
145- const newValue = ! ( alwaysAllowMcp ?? false )
146- setAlwaysAllowMcp ( newValue )
147- vscode . postMessage ( { type : "alwaysAllowMcp" , bool : newValue } )
148- } , [ alwaysAllowMcp , setAlwaysAllowMcp ] )
149-
150- const handleModeSwitchChange = useCallback ( ( ) => {
151- const newValue = ! ( alwaysAllowModeSwitch ?? false )
152- setAlwaysAllowModeSwitch ( newValue )
153- vscode . postMessage ( { type : "alwaysAllowModeSwitch" , bool : newValue } )
154- } , [ alwaysAllowModeSwitch , setAlwaysAllowModeSwitch ] )
155-
156- const handleSubtasksChange = useCallback ( ( ) => {
157- const newValue = ! ( alwaysAllowSubtasks ?? false )
158- setAlwaysAllowSubtasks ( newValue )
159- vscode . postMessage ( { type : "alwaysAllowSubtasks" , bool : newValue } )
160- } , [ alwaysAllowSubtasks , setAlwaysAllowSubtasks ] )
161-
162- const handleRetryChange = useCallback ( ( ) => {
163- const newValue = ! ( alwaysApproveResubmit ?? false )
164- setAlwaysApproveResubmit ( newValue )
165- vscode . postMessage ( { type : "alwaysApproveResubmit" , bool : newValue } )
166- } , [ alwaysApproveResubmit , setAlwaysApproveResubmit ] )
167-
168- const handleOpenSettings = useCallback ( ( ) => {
169- window . postMessage ( {
170- type : "action" ,
171- action : "settingsButtonClicked" ,
172- values : { section : "autoApprove" } ,
173- } )
174- } , [ ] )
175-
176- // Map action IDs to their specific handlers.
177- const actionHandlers : Record < AutoApproveAction [ "id" ] , ( ) => void > = {
178- readFiles : handleReadOnlyChange ,
179- editFiles : handleWriteChange ,
180- executeCommands : handleExecuteChange ,
181- useBrowser : handleBrowserChange ,
182- useMcp : handleMcpChange ,
183- switchModes : handleModeSwitchChange ,
184- subtasks : handleSubtasksChange ,
185- retryRequests : handleRetryChange ,
186- }
113+ const handleOpenSettings = useCallback (
114+ ( ) =>
115+ window . postMessage ( { type : "action" , action : "settingsButtonClicked" , values : { section : "autoApprove" } } ) ,
116+ [ ] ,
117+ )
187118
188119 return (
189120 < div
@@ -250,6 +181,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
250181 />
251182 </ div >
252183 </ div >
184+
253185 { isExpanded && (
254186 < div className = "flex flex-col gap-2" >
255187 < div
@@ -264,27 +196,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
264196 } }
265197 />
266198 </ div >
267- < div className = "grid grid-cols-2 [@media(min-width:320px)]:grid-cols-4 gap-2" >
268- { actions . map ( ( action ) => {
269- const codicon = ICON_MAP [ action . id ] || "question"
270- return (
271- < Button
272- key = { action . id }
273- variant = { action . enabled ? "default" : "ghost" }
274- onClick = { ( e ) => {
275- e . stopPropagation ( )
276- actionHandlers [ action . id ] ( )
277- } }
278- title = { action . description }
279- className = "h-12" >
280- < span className = "flex flex-col items-center gap-1" >
281- < span className = { `codicon codicon-${ codicon } ` } />
282- < span className = "text-sm text-center" > { action . label } </ span >
283- </ span >
284- </ Button >
285- )
286- } ) }
287- </ div >
199+ < AutoApproveToggle { ...toggles } onToggle = { onAutoApproveToggle } />
288200 </ div >
289201 ) }
290202 </ div >
0 commit comments