Skip to content

Commit 6cf376f

Browse files
fix: Resolve confusing auto-approve checkbox states (RooCodeInc#5602)
Co-authored-by: Daniel Riccio <[email protected]>
1 parent 2458751 commit 6cf376f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1414
-81
lines changed

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

Lines changed: 76 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import { vscode } from "@src/utils/vscode"
66
import { useExtensionState } from "@src/context/ExtensionStateContext"
77
import { useAppTranslation } from "@src/i18n/TranslationContext"
88
import { AutoApproveToggle, AutoApproveSetting, autoApproveSettingsConfig } from "../settings/AutoApproveToggle"
9+
import { StandardTooltip } from "@src/components/ui"
10+
import { useAutoApprovalState } from "@src/hooks/useAutoApprovalState"
11+
import { useAutoApprovalToggles } from "@src/hooks/useAutoApprovalToggles"
912

1013
interface AutoApproveMenuProps {
1114
style?: React.CSSProperties
@@ -17,16 +20,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
1720
const {
1821
autoApprovalEnabled,
1922
setAutoApprovalEnabled,
20-
alwaysAllowReadOnly,
21-
alwaysAllowWrite,
22-
alwaysAllowExecute,
23-
alwaysAllowBrowser,
24-
alwaysAllowMcp,
25-
alwaysAllowModeSwitch,
26-
alwaysAllowSubtasks,
2723
alwaysApproveResubmit,
28-
alwaysAllowFollowupQuestions,
29-
alwaysAllowUpdateTodoList,
3024
allowedMaxRequests,
3125
setAlwaysAllowReadOnly,
3226
setAlwaysAllowWrite,
@@ -43,10 +37,24 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
4337

4438
const { t } = useAppTranslation()
4539

40+
const baseToggles = useAutoApprovalToggles()
41+
42+
// AutoApproveMenu needs alwaysApproveResubmit in addition to the base toggles
43+
const toggles = useMemo(
44+
() => ({
45+
...baseToggles,
46+
alwaysApproveResubmit: alwaysApproveResubmit,
47+
}),
48+
[baseToggles, alwaysApproveResubmit],
49+
)
50+
51+
const { hasEnabledOptions, effectiveAutoApprovalEnabled } = useAutoApprovalState(toggles, autoApprovalEnabled)
52+
4653
const onAutoApproveToggle = useCallback(
4754
(key: AutoApproveSetting, value: boolean) => {
4855
vscode.postMessage({ type: key, bool: value })
4956

57+
// Update the specific toggle state
5058
switch (key) {
5159
case "alwaysAllowReadOnly":
5260
setAlwaysAllowReadOnly(value)
@@ -79,8 +87,30 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
7987
setAlwaysAllowUpdateTodoList(value)
8088
break
8189
}
90+
91+
// Check if we need to update the master auto-approval state
92+
// Create a new toggles state with the updated value
93+
const updatedToggles = {
94+
...toggles,
95+
[key]: value,
96+
}
97+
98+
const willHaveEnabledOptions = Object.values(updatedToggles).some((v) => !!v)
99+
100+
// If enabling the first option, enable master auto-approval
101+
if (value && !hasEnabledOptions && willHaveEnabledOptions) {
102+
setAutoApprovalEnabled(true)
103+
vscode.postMessage({ type: "autoApprovalEnabled", bool: true })
104+
}
105+
// If disabling the last option, disable master auto-approval
106+
else if (!value && hasEnabledOptions && !willHaveEnabledOptions) {
107+
setAutoApprovalEnabled(false)
108+
vscode.postMessage({ type: "autoApprovalEnabled", bool: false })
109+
}
82110
},
83111
[
112+
toggles,
113+
hasEnabledOptions,
84114
setAlwaysAllowReadOnly,
85115
setAlwaysAllowWrite,
86116
setAlwaysAllowExecute,
@@ -91,43 +121,32 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
91121
setAlwaysApproveResubmit,
92122
setAlwaysAllowFollowupQuestions,
93123
setAlwaysAllowUpdateTodoList,
124+
setAutoApprovalEnabled,
94125
],
95126
)
96127

97-
const toggleExpanded = useCallback(() => setIsExpanded((prev) => !prev), [])
128+
const toggleExpanded = useCallback(() => {
129+
setIsExpanded((prev) => !prev)
130+
}, [])
98131

99-
const toggles = useMemo(
100-
() => ({
101-
alwaysAllowReadOnly: alwaysAllowReadOnly,
102-
alwaysAllowWrite: alwaysAllowWrite,
103-
alwaysAllowExecute: alwaysAllowExecute,
104-
alwaysAllowBrowser: alwaysAllowBrowser,
105-
alwaysAllowMcp: alwaysAllowMcp,
106-
alwaysAllowModeSwitch: alwaysAllowModeSwitch,
107-
alwaysAllowSubtasks: alwaysAllowSubtasks,
108-
alwaysApproveResubmit: alwaysApproveResubmit,
109-
alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions,
110-
alwaysAllowUpdateTodoList: alwaysAllowUpdateTodoList,
111-
}),
112-
[
113-
alwaysAllowReadOnly,
114-
alwaysAllowWrite,
115-
alwaysAllowExecute,
116-
alwaysAllowBrowser,
117-
alwaysAllowMcp,
118-
alwaysAllowModeSwitch,
119-
alwaysAllowSubtasks,
120-
alwaysApproveResubmit,
121-
alwaysAllowFollowupQuestions,
122-
alwaysAllowUpdateTodoList,
123-
],
124-
)
132+
// Disable main checkbox while menu is open or no options selected
133+
const isCheckboxDisabled = useMemo(() => {
134+
return !hasEnabledOptions || isExpanded
135+
}, [hasEnabledOptions, isExpanded])
125136

126137
const enabledActionsList = Object.entries(toggles)
127138
.filter(([_key, value]) => !!value)
128139
.map(([key]) => t(autoApproveSettingsConfig[key as AutoApproveSetting].labelKey))
129140
.join(", ")
130141

142+
// Update displayed text logic
143+
const displayText = useMemo(() => {
144+
if (!effectiveAutoApprovalEnabled || !hasEnabledOptions) {
145+
return t("chat:autoApprove.none")
146+
}
147+
return enabledActionsList || t("chat:autoApprove.none")
148+
}, [effectiveAutoApprovalEnabled, hasEnabledOptions, enabledActionsList, t])
149+
131150
const handleOpenSettings = useCallback(
132151
() =>
133152
window.postMessage({ type: "action", action: "settingsButtonClicked", values: { section: "autoApprove" } }),
@@ -155,14 +174,26 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
155174
}}
156175
onClick={toggleExpanded}>
157176
<div onClick={(e) => e.stopPropagation()}>
158-
<VSCodeCheckbox
159-
checked={autoApprovalEnabled ?? false}
160-
onChange={() => {
161-
const newValue = !(autoApprovalEnabled ?? false)
162-
setAutoApprovalEnabled(newValue)
163-
vscode.postMessage({ type: "autoApprovalEnabled", bool: newValue })
164-
}}
165-
/>
177+
<StandardTooltip
178+
content={!hasEnabledOptions ? t("chat:autoApprove.selectOptionsFirst") : undefined}>
179+
<VSCodeCheckbox
180+
checked={effectiveAutoApprovalEnabled}
181+
disabled={isCheckboxDisabled}
182+
aria-label={
183+
hasEnabledOptions
184+
? t("chat:autoApprove.toggleAriaLabel")
185+
: t("chat:autoApprove.disabledAriaLabel")
186+
}
187+
onChange={() => {
188+
if (hasEnabledOptions) {
189+
const newValue = !(autoApprovalEnabled ?? false)
190+
setAutoApprovalEnabled(newValue)
191+
vscode.postMessage({ type: "autoApprovalEnabled", bool: newValue })
192+
}
193+
// If no options enabled, do nothing
194+
}}
195+
/>
196+
</StandardTooltip>
166197
</div>
167198
<div
168199
style={{
@@ -188,7 +219,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
188219
flex: 1,
189220
minWidth: 0,
190221
}}>
191-
{enabledActionsList || t("chat:autoApprove.none")}
222+
{displayText}
192223
</span>
193224
<span
194225
className={`codicon codicon-chevron-${isExpanded ? "down" : "right"}`}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import { useSelectedModel } from "@src/components/ui/hooks/useSelectedModel"
3838
import RooHero from "@src/components/welcome/RooHero"
3939
import RooTips from "@src/components/welcome/RooTips"
4040
import { StandardTooltip } from "@src/components/ui"
41+
import { useAutoApprovalState } from "@src/hooks/useAutoApprovalState"
42+
import { useAutoApprovalToggles } from "@src/hooks/useAutoApprovalToggles"
4143

4244
import TelemetryBanner from "../common/TelemetryBanner"
4345
import VersionIndicator from "../common/VersionIndicator"
@@ -959,12 +961,23 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
959961
[deniedCommands],
960962
)
961963

964+
// Create toggles object for useAutoApprovalState hook
965+
const autoApprovalToggles = useAutoApprovalToggles()
966+
967+
const { hasEnabledOptions } = useAutoApprovalState(autoApprovalToggles, autoApprovalEnabled)
968+
962969
const isAutoApproved = useCallback(
963970
(message: ClineMessage | undefined) => {
971+
// First check if auto-approval is enabled AND we have at least one permission
964972
if (!autoApprovalEnabled || !message || message.type !== "ask") {
965973
return false
966974
}
967975

976+
// Use the hook's result instead of duplicating the logic
977+
if (!hasEnabledOptions) {
978+
return false
979+
}
980+
968981
if (message.ask === "followup") {
969982
return alwaysAllowFollowupQuestions
970983
}
@@ -1038,6 +1051,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
10381051
},
10391052
[
10401053
autoApprovalEnabled,
1054+
hasEnabledOptions,
10411055
alwaysAllowBrowser,
10421056
alwaysAllowReadOnly,
10431057
alwaysAllowReadOnlyOutsideWorkspace,

0 commit comments

Comments
 (0)