Skip to content

Commit 7b58d75

Browse files
committed
#2579 UI fixes for Auto Approve
1 parent 3f3825a commit 7b58d75

File tree

3 files changed

+73
-25
lines changed

3 files changed

+73
-25
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ node_modules
66
coverage/
77
mock/
88

9+
# Webview UI specific ignores
10+
webview-ui/node_modules
11+
webview-ui/dist
12+
913
.DS_Store
1014

1115
# IDEs

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

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
4343
(key: AutoApproveSetting, value: boolean) => {
4444
vscode.postMessage({ type: key, bool: value })
4545

46+
// Update the specific setting
4647
switch (key) {
4748
case "alwaysAllowReadOnly":
4849
setAlwaysAllowReadOnly(value)
@@ -69,6 +70,29 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
6970
setAlwaysApproveResubmit(value)
7071
break
7172
}
73+
74+
// After updating the specific setting, check if any action is now enabled.
75+
// If so, ensure autoApprovalEnabled is true.
76+
// This needs to be done after the state updates, so we'll use a temporary check
77+
// or re-evaluate the `toggles` object.
78+
// For simplicity, we'll assume the `toggles` state will reflect the change
79+
// in the next render cycle, and we can force autoApprovalEnabled to true
80+
// if any action is being enabled.
81+
if (value === true) {
82+
setAutoApprovalEnabled(true)
83+
vscode.postMessage({ type: "autoApprovalEnabled", bool: true })
84+
} else {
85+
// If an action is being disabled, check if all are now disabled.
86+
// If so, set autoApprovalEnabled to false.
87+
// This requires re-evaluating the state of all toggles *after* the current one is set.
88+
// A more robust solution would involve passing the updated `toggles` object
89+
// or re-calculating `hasAnyAutoApprovedAction` here.
90+
// For now, let's rely on the `hasAnyAutoApprovedAction` memoized value
91+
// which will update on the next render.
92+
// If the user unchecks the last enabled option, autoApprovalEnabled should become false.
93+
// This logic is already handled by the main checkbox's disabled state in the collapsed view.
94+
// So, we only need to ensure it turns ON when an individual is turned ON.
95+
}
7296
},
7397
[
7498
setAlwaysAllowReadOnly,
@@ -79,6 +103,8 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
79103
setAlwaysAllowModeSwitch,
80104
setAlwaysAllowSubtasks,
81105
setAlwaysApproveResubmit,
106+
setAutoApprovalEnabled, // Added setAutoApprovalEnabled to dependencies
107+
vscode, // Added vscode to dependencies
82108
],
83109
)
84110

@@ -107,10 +133,20 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
107133
],
108134
)
109135

110-
const enabledActionsList = Object.entries(toggles)
111-
.filter(([_key, value]) => !!value)
112-
.map(([key]) => t(autoApproveSettingsConfig[key as AutoApproveSetting].labelKey))
113-
.join(", ")
136+
const hasAnyAutoApprovedAction = useMemo(
137+
() => Object.values(toggles).some((value) => !!value),
138+
[toggles],
139+
)
140+
141+
const displayedAutoApproveText = useMemo(() => {
142+
if (autoApprovalEnabled && hasAnyAutoApprovedAction) {
143+
return Object.entries(toggles)
144+
.filter(([_key, value]) => !!value)
145+
.map(([key]) => t(autoApproveSettingsConfig[key as AutoApproveSetting].labelKey))
146+
.join(", ")
147+
}
148+
return t("chat:autoApprove.none")
149+
}, [autoApprovalEnabled, hasAnyAutoApprovedAction, toggles, t])
114150

115151
const handleOpenSettings = useCallback(
116152
() =>
@@ -140,9 +176,10 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
140176
onClick={toggleExpanded}>
141177
<div onClick={(e) => e.stopPropagation()}>
142178
<VSCodeCheckbox
143-
checked={autoApprovalEnabled ?? false}
179+
checked={autoApprovalEnabled && hasAnyAutoApprovedAction}
180+
disabled={!hasAnyAutoApprovedAction}
144181
onChange={() => {
145-
const newValue = !(autoApprovalEnabled ?? false)
182+
const newValue = !(autoApprovalEnabled && hasAnyAutoApprovedAction)
146183
setAutoApprovalEnabled(newValue)
147184
vscode.postMessage({ type: "autoApprovalEnabled", bool: newValue })
148185
}}
@@ -172,7 +209,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
172209
flex: 1,
173210
minWidth: 0,
174211
}}>
175-
{enabledActionsList || t("chat:autoApprove.none")}
212+
{displayedAutoApproveText}
176213
</span>
177214
<span
178215
className={`codicon codicon-chevron-${isExpanded ? "down" : "right"}`}
@@ -199,7 +236,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
199236
/>
200237
</div>
201238

202-
<AutoApproveToggle {...toggles} onToggle={onAutoApproveToggle} />
239+
<AutoApproveToggle {...toggles} onToggle={onAutoApproveToggle} isOverallApprovalEnabled={autoApprovalEnabled} />
203240

204241
{/* Auto-approve API request count limit input row inspired by Cline */}
205242
<div

webview-ui/src/components/settings/AutoApproveToggle.tsx

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@ export const autoApproveSettingsConfig: Record<AutoApproveSetting, AutoApproveCo
8787

8888
type AutoApproveToggleProps = AutoApproveToggles & {
8989
onToggle: (key: AutoApproveSetting, value: boolean) => void
90+
isOverallApprovalEnabled?: boolean // New prop
9091
}
9192

92-
export const AutoApproveToggle = ({ onToggle, ...props }: AutoApproveToggleProps) => {
93+
export const AutoApproveToggle = ({ onToggle, isOverallApprovalEnabled, ...props }: AutoApproveToggleProps) => {
9394
const { t } = useAppTranslation()
9495

9596
return (
@@ -99,22 +100,28 @@ export const AutoApproveToggle = ({ onToggle, ...props }: AutoApproveToggleProps
99100
"[@media(min-width:600px)]:gap-4",
100101
"[@media(min-width:800px)]:max-w-[800px]",
101102
)}>
102-
{Object.values(autoApproveSettingsConfig).map(({ key, descriptionKey, labelKey, icon, testId }) => (
103-
<Button
104-
key={key}
105-
variant={props[key] ? "default" : "outline"}
106-
onClick={() => onToggle(key, !props[key])}
107-
title={t(descriptionKey || "")}
108-
aria-label={t(labelKey)}
109-
aria-pressed={!!props[key]}
110-
data-testid={testId}
111-
className={cn(" aspect-square h-[80px]", !props[key] && "opacity-50")}>
112-
<span className={cn("flex flex-col items-center gap-1")}>
113-
<span className={`codicon codicon-${icon}`} />
114-
<span className="text-sm text-center">{t(labelKey)}</span>
115-
</span>
116-
</Button>
117-
))}
103+
{Object.values(autoApproveSettingsConfig).map(({ key, descriptionKey, labelKey, icon, testId }) => {
104+
const isButtonActive = props[key] // This reflects the actual state of the individual toggle
105+
const isButtonVisuallyEnabled = isOverallApprovalEnabled === false ? false : isButtonActive
106+
107+
return (
108+
<Button
109+
key={key}
110+
variant={isButtonActive ? "default" : "outline"} // Variant always reflects its own state
111+
onClick={() => onToggle(key, !props[key])}
112+
title={t(descriptionKey || "")}
113+
aria-label={t(labelKey)}
114+
aria-pressed={!!isButtonActive}
115+
data-testid={testId}
116+
className={cn(" aspect-square h-[80px]", !isButtonVisuallyEnabled && "opacity-50")} // Opacity based on overall state
117+
>
118+
<span className={cn("flex flex-col items-center gap-1")}>
119+
<span className={`codicon codicon-${icon}`} />
120+
<span className="text-sm text-center">{t(labelKey)}</span>
121+
</span>
122+
</Button>
123+
)
124+
})}
118125
</div>
119126
)
120127
}

0 commit comments

Comments
 (0)