Skip to content

Commit cec338b

Browse files
committed
DRY up the auto-approve toggles
1 parent e7a57ea commit cec338b

File tree

18 files changed

+256
-810
lines changed

18 files changed

+256
-810
lines changed

webview-ui/src/components/chat/AutoApproveMenu.tsx

Lines changed: 88 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -1,189 +1,120 @@
1-
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
2-
import { useCallback, useState } from "react"
1+
import { useCallback, useMemo, useState } from "react"
32
import { 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

85
import { vscode } from "../../utils/vscode"
96
import { useExtensionState } from "../../context/ExtensionStateContext"
107
import { 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

3010
interface AutoApproveMenuProps {
3111
style?: React.CSSProperties
3212
}
3313

3414
const 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

Comments
 (0)