Clean up the auto-approve UI (#6538)

* Clean up the auto-approve UI

* Update webview-ui/src/components/settings/AutoApproveSettings.tsx

Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>

* Fix

* Translations

---------

Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
This commit is contained in:
Matt Rubens 2025-08-01 07:49:42 -04:00 committed by GitHub
parent 836371c36a
commit 305a5da369
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 110 additions and 102 deletions

View file

@ -6,7 +6,6 @@ import { vscode } from "@src/utils/vscode"
import { useExtensionState } from "@src/context/ExtensionStateContext"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { AutoApproveToggle, AutoApproveSetting, autoApproveSettingsConfig } from "../settings/AutoApproveToggle"
import { MaxLimitInputs } from "../settings/MaxLimitInputs"
import { StandardTooltip } from "@src/components/ui"
import { useAutoApprovalState } from "@src/hooks/useAutoApprovalState"
import { useAutoApprovalToggles } from "@src/hooks/useAutoApprovalToggles"
@ -22,8 +21,6 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
autoApprovalEnabled,
setAutoApprovalEnabled,
alwaysApproveResubmit,
allowedMaxRequests,
allowedMaxCost,
setAlwaysAllowReadOnly,
setAlwaysAllowWrite,
setAlwaysAllowExecute,
@ -34,8 +31,6 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
setAlwaysApproveResubmit,
setAlwaysAllowFollowupQuestions,
setAlwaysAllowUpdateTodoList,
setAllowedMaxRequests,
setAllowedMaxCost,
} = useExtensionState()
const { t } = useAppTranslation()
@ -245,13 +240,6 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
</div>
<AutoApproveToggle {...toggles} onToggle={onAutoApproveToggle} />
<MaxLimitInputs
allowedMaxRequests={allowedMaxRequests ?? undefined}
allowedMaxCost={allowedMaxCost ?? undefined}
onMaxRequestsChange={(value) => setAllowedMaxRequests(value)}
onMaxCostChange={(value) => setAllowedMaxCost(value)}
/>
</div>
)}
</div>

View file

@ -1,5 +1,5 @@
import { HTMLAttributes, useState } from "react"
import { X } from "lucide-react"
import { X, CheckCheck } from "lucide-react"
import { useAppTranslation } from "@/i18n/TranslationContext"
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
@ -114,57 +114,68 @@ export const AutoApproveSettings = ({
return (
<div {...props}>
<SectionHeader description={t("settings:autoApprove.description")}>
<SectionHeader>
<div className="flex items-center gap-2">
{!hasEnabledOptions ? (
<StandardTooltip content={t("settings:autoApprove.selectOptionsFirst")}>
<VSCodeCheckbox
checked={effectiveAutoApprovalEnabled}
disabled={!hasEnabledOptions}
aria-label={t("settings:autoApprove.disabledAriaLabel")}
onChange={() => {
// Do nothing when no options are enabled
return
}}
/>
</StandardTooltip>
) : (
<VSCodeCheckbox
checked={effectiveAutoApprovalEnabled}
disabled={!hasEnabledOptions}
aria-label={t("settings:autoApprove.toggleAriaLabel")}
onChange={() => {
const newValue = !(autoApprovalEnabled ?? false)
setAutoApprovalEnabled(newValue)
vscode.postMessage({ type: "autoApprovalEnabled", bool: newValue })
}}
/>
)}
<span className="codicon codicon-check w-4" />
<CheckCheck className="w-4 h-4" />
<div>{t("settings:sections.autoApprove")}</div>
</div>
</SectionHeader>
<Section>
<AutoApproveToggle
alwaysAllowReadOnly={alwaysAllowReadOnly}
alwaysAllowWrite={alwaysAllowWrite}
alwaysAllowBrowser={alwaysAllowBrowser}
alwaysApproveResubmit={alwaysApproveResubmit}
alwaysAllowMcp={alwaysAllowMcp}
alwaysAllowModeSwitch={alwaysAllowModeSwitch}
alwaysAllowSubtasks={alwaysAllowSubtasks}
alwaysAllowExecute={alwaysAllowExecute}
alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions}
alwaysAllowUpdateTodoList={alwaysAllowUpdateTodoList}
onToggle={(key, value) => setCachedStateField(key, value)}
/>
<MaxLimitInputs
allowedMaxRequests={allowedMaxRequests}
allowedMaxCost={allowedMaxCost}
onMaxRequestsChange={(value) => setCachedStateField("allowedMaxRequests", value)}
onMaxCostChange={(value) => setCachedStateField("allowedMaxCost", value)}
/>
<div className="space-y-4">
<div>
{!hasEnabledOptions ? (
<StandardTooltip content={t("settings:autoApprove.selectOptionsFirst")}>
<VSCodeCheckbox
checked={effectiveAutoApprovalEnabled}
disabled={!hasEnabledOptions}
aria-label={t("settings:autoApprove.disabledAriaLabel")}
onChange={() => {
// Do nothing when no options are enabled
return
}}>
<span className="font-medium">{t("settings:autoApprove.enabled")}</span>
</VSCodeCheckbox>
</StandardTooltip>
) : (
<VSCodeCheckbox
checked={effectiveAutoApprovalEnabled}
disabled={!hasEnabledOptions}
aria-label={t("settings:autoApprove.toggleAriaLabel")}
onChange={() => {
const newValue = !(autoApprovalEnabled ?? false)
setAutoApprovalEnabled(newValue)
vscode.postMessage({ type: "autoApprovalEnabled", bool: newValue })
}}>
<span className="font-medium">{t("settings:autoApprove.enabled")}</span>
</VSCodeCheckbox>
)}
<div className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:autoApprove.description")}
</div>
</div>
<AutoApproveToggle
alwaysAllowReadOnly={alwaysAllowReadOnly}
alwaysAllowWrite={alwaysAllowWrite}
alwaysAllowBrowser={alwaysAllowBrowser}
alwaysApproveResubmit={alwaysApproveResubmit}
alwaysAllowMcp={alwaysAllowMcp}
alwaysAllowModeSwitch={alwaysAllowModeSwitch}
alwaysAllowSubtasks={alwaysAllowSubtasks}
alwaysAllowExecute={alwaysAllowExecute}
alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions}
alwaysAllowUpdateTodoList={alwaysAllowUpdateTodoList}
onToggle={(key, value) => setCachedStateField(key, value)}
/>
<MaxLimitInputs
allowedMaxRequests={allowedMaxRequests}
allowedMaxCost={allowedMaxCost}
onMaxRequestsChange={(value) => setCachedStateField("allowedMaxRequests", value)}
onMaxCostChange={(value) => setCachedStateField("allowedMaxCost", value)}
/>
</div>
{/* ADDITIONAL SETTINGS */}

View file

@ -109,13 +109,7 @@ export const AutoApproveToggle = ({ onToggle, ...props }: AutoApproveToggleProps
const { t } = useAppTranslation()
return (
<div
className={cn(
"flex flex-row flex-wrap justify-center gap-2 max-w-[600px] mx-auto my-2 ",
"[@media(min-width:600px)]:gap-4",
"[@media(min-width:800px)]:max-w-[900px]",
"[@media(min-width:1200px)]:max-w-[1800px]",
)}>
<div className={cn("flex flex-row flex-wrap gap-2 py-2")}>
{Object.values(autoApproveSettingsConfig).map(({ key, descriptionKey, labelKey, icon, testId }) => (
<StandardTooltip key={key} content={t(descriptionKey || "")}>
<Button
@ -124,11 +118,12 @@ export const AutoApproveToggle = ({ onToggle, ...props }: AutoApproveToggleProps
aria-label={t(labelKey)}
aria-pressed={!!props[key]}
data-testid={testId}
className={cn(" aspect-square h-[80px]", !props[key] && "opacity-50")}>
<span className={cn("flex flex-col items-center gap-1")}>
<span className={`codicon codicon-${icon}`} />
<span className="text-sm text-center">{t(labelKey)}</span>
</span>
className={cn(
"h-7 px-2 rounded-md flex items-center gap-1.5 text-xs whitespace-nowrap",
!props[key] && "opacity-50",
)}>
<span className={`codicon codicon-${icon} text-sm`} />
<span>{t(labelKey)}</span>
</Button>
</StandardTooltip>
))}

View file

@ -20,22 +20,20 @@ export function MaxCostInput({ allowedMaxCost, onValueChange }: MaxCostInputProp
)
return (
<div className="flex flex-col gap-3 pl-3 flex-auto">
<div className="flex items-center gap-4 font-bold">
<>
<label className="flex items-center gap-2 text-sm font-medium whitespace-nowrap">
<span className="codicon codicon-credit-card" />
<div>{t("settings:autoApprove.apiCostLimit.title")}</div>
</div>
<div className="flex items-center">
<FormattedTextField
value={allowedMaxCost}
onValueChange={handleValueChange}
formatter={unlimitedDecimalFormatter}
placeholder={t("settings:autoApprove.apiCostLimit.unlimited")}
style={{ flex: 1, maxWidth: "200px" }}
data-testid="max-cost-input"
leftNodes={[<span key="dollar">$</span>]}
/>
</div>
</div>
{t("settings:autoApprove.apiCostLimit.title")}:
</label>
<FormattedTextField
value={allowedMaxCost}
onValueChange={handleValueChange}
formatter={unlimitedDecimalFormatter}
placeholder={t("settings:autoApprove.apiCostLimit.unlimited")}
style={{ maxWidth: "200px" }}
data-testid="max-cost-input"
leftNodes={[<span key="dollar">$</span>]}
/>
</>
)
}

View file

@ -20,7 +20,7 @@ export const MaxLimitInputs: React.FC<MaxLimitInputsProps> = ({
return (
<div className="space-y-2">
<div className="flex justify-stretch">
<div className="grid grid-cols-[auto_1fr] gap-x-2 gap-y-2 items-center">
<MaxRequestsInput allowedMaxRequests={allowedMaxRequests} onValueChange={onMaxRequestsChange} />
<MaxCostInput allowedMaxCost={allowedMaxCost} onValueChange={onMaxCostChange} />
</div>

View file

@ -20,21 +20,19 @@ export function MaxRequestsInput({ allowedMaxRequests, onValueChange }: MaxReque
)
return (
<div className="flex flex-col gap-3 pl-3 flex-auto">
<div className="flex items-center gap-4 font-bold">
<>
<label className="flex items-center gap-2 text-sm font-medium whitespace-nowrap">
<span className="codicon codicon-pulse" />
<div>{t("settings:autoApprove.apiRequestLimit.title")}</div>
</div>
<div className="flex items-center gap-2">
<FormattedTextField
value={allowedMaxRequests}
onValueChange={handleValueChange}
formatter={unlimitedIntegerFormatter}
placeholder={t("settings:autoApprove.apiRequestLimit.unlimited")}
style={{ flex: 1, maxWidth: "200px" }}
data-testid="max-requests-input"
/>
</div>
</div>
{t("settings:autoApprove.apiRequestLimit.title")}:
</label>
<FormattedTextField
value={allowedMaxRequests}
onValueChange={handleValueChange}
formatter={unlimitedIntegerFormatter}
placeholder={t("settings:autoApprove.apiRequestLimit.unlimited")}
style={{ maxWidth: "200px" }}
data-testid="max-requests-input"
/>
</>
)
}

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Permet que Roo realitzi operacions automàticament sense requerir aprovació. Activeu aquesta configuració només si confieu plenament en la IA i enteneu els riscos de seguretat associats.",
"enabled": "Auto-aprovació activada",
"toggleAriaLabel": "Commuta l'aprovació automàtica",
"disabledAriaLabel": "Aprovació automàtica desactivada: seleccioneu primer les opcions",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Erlaubt Roo, Operationen automatisch ohne Genehmigung durchzuführen. Aktiviere diese Einstellungen nur, wenn du der KI vollständig vertraust und die damit verbundenen Sicherheitsrisiken verstehst.",
"enabled": "Auto-Genehmigung aktiviert",
"toggleAriaLabel": "Automatische Genehmigung umschalten",
"disabledAriaLabel": "Automatische Genehmigung deaktiviert - zuerst Optionen auswählen",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Allow Roo to automatically perform operations without requiring approval. Enable these settings only if you fully trust the AI and understand the associated security risks.",
"enabled": "Auto-Approve Enabled",
"readOnly": {
"label": "Read",
"description": "When enabled, Roo will automatically view directory contents and read files without requiring you to click the Approve button.",

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Permitir que Roo realice operaciones automáticamente sin requerir aprobación. Habilite esta configuración solo si confía plenamente en la IA y comprende los riesgos de seguridad asociados.",
"enabled": "Auto-aprobación habilitada",
"toggleAriaLabel": "Alternar aprobación automática",
"disabledAriaLabel": "Aprobación automática desactivada: seleccione primero las opciones",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Permettre à Roo d'effectuer automatiquement des opérations sans requérir d'approbation. Activez ces paramètres uniquement si vous faites entièrement confiance à l'IA et que vous comprenez les risques de sécurité associés.",
"enabled": "Auto-approbation activée",
"toggleAriaLabel": "Activer/désactiver l'approbation automatique",
"disabledAriaLabel": "Approbation automatique désactivée - sélectionnez d'abord les options",
"selectOptionsFirst": "Sélectionnez au moins une option ci-dessous pour activer l'approbation automatique",

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Roo को अनुमोदन की आवश्यकता के बिना स्वचालित रूप से ऑपरेशन करने की अनुमति दें। इन सेटिंग्स को केवल तभी सक्षम करें जब आप AI पर पूरी तरह से भरोसा करते हों और संबंधित सुरक्षा जोखिमों को समझते हों।",
"enabled": "स्वत:-अनुमोदन सक्षम",
"toggleAriaLabel": "स्वतः-अनुमोदन टॉगल करें",
"disabledAriaLabel": "स्वतः-अनुमोदन अक्षम - पहले विकल्प चुनें",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Izinkan Roo untuk secara otomatis melakukan operasi tanpa memerlukan persetujuan. Aktifkan pengaturan ini hanya jika kamu sepenuhnya mempercayai AI dan memahami risiko keamanan yang terkait.",
"enabled": "Auto-Approve Diaktifkan",
"toggleAriaLabel": "Beralih persetujuan otomatis",
"disabledAriaLabel": "Persetujuan otomatis dinonaktifkan - pilih opsi terlebih dahulu",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Permetti a Roo di eseguire automaticamente operazioni senza richiedere approvazione. Abilita queste impostazioni solo se ti fidi completamente dell'IA e comprendi i rischi di sicurezza associati.",
"enabled": "Auto-approvazione abilitata",
"toggleAriaLabel": "Attiva/disattiva approvazione automatica",
"disabledAriaLabel": "Approvazione automatica disabilitata - seleziona prima le opzioni",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Rooが承認なしで自動的に操作を実行できるようにします。AIを完全に信頼し、関連するセキュリティリスクを理解している場合にのみ、これらの設定を有効にしてください。",
"enabled": "自動承認が有効",
"toggleAriaLabel": "自動承認の切り替え",
"disabledAriaLabel": "自動承認が無効です - 最初にオプションを選択してください",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Roo가 승인 없이 자동으로 작업을 수행할 수 있도록 허용합니다. AI를 완전히 신뢰하고 관련 보안 위험을 이해하는 경우에만 이러한 설정을 활성화하세요.",
"enabled": "자동 승인 활성화됨",
"toggleAriaLabel": "자동 승인 전환",
"disabledAriaLabel": "자동 승인 비활성화됨 - 먼저 옵션을 선택하세요",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Sta Roo toe om automatisch handelingen uit te voeren zonder goedkeuring. Schakel deze instellingen alleen in als je de AI volledig vertrouwt en de bijbehorende beveiligingsrisico's begrijpt.",
"enabled": "Auto-goedkeuren ingeschakeld",
"toggleAriaLabel": "Automatisch goedkeuren in-/uitschakelen",
"disabledAriaLabel": "Automatisch goedkeuren uitgeschakeld - selecteer eerst opties",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Pozwól Roo na automatyczne wykonywanie operacji bez wymagania zatwierdzenia. Włącz te ustawienia tylko jeśli w pełni ufasz AI i rozumiesz związane z tym zagrożenia bezpieczeństwa.",
"enabled": "Auto-zatwierdzanie włączone",
"toggleAriaLabel": "Przełącz automatyczne zatwierdzanie",
"disabledAriaLabel": "Automatyczne zatwierdzanie wyłączone - najpierw wybierz opcje",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Permitir que o Roo realize operações automaticamente sem exigir aprovação. Ative essas configurações apenas se confiar totalmente na IA e compreender os riscos de segurança associados.",
"enabled": "Aprovação automática habilitada",
"toggleAriaLabel": "Alternar aprovação automática",
"disabledAriaLabel": "Aprovação automática desativada - selecione as opções primeiro",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Разрешить Roo автоматически выполнять операции без необходимости одобрения. Включайте эти параметры только если полностью доверяете ИИ и понимаете связанные с этим риски безопасности.",
"enabled": "Автоодобрение включено",
"toggleAriaLabel": "Переключить автоодобрение",
"disabledAriaLabel": "Автоодобрение отключено - сначала выберите опции",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Roo'nun onay gerektirmeden otomatik olarak işlemler gerçekleştirmesine izin verin. Bu ayarları yalnızca yapay zekaya tamamen güveniyorsanız ve ilgili güvenlik risklerini anlıyorsanız etkinleştirin.",
"enabled": "Oto-onay etkinleştirildi",
"toggleAriaLabel": "Otomatik onayı değiştir",
"disabledAriaLabel": "Otomatik onay devre dışı - önce seçenekleri belirleyin",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "Cho phép Roo tự động thực hiện các hoạt động mà không cần phê duyệt. Chỉ bật những cài đặt này nếu bạn hoàn toàn tin tưởng AI và hiểu rõ các rủi ro bảo mật liên quan.",
"enabled": "Phê duyệt tự động đã bật",
"toggleAriaLabel": "Chuyển đổi tự động phê duyệt",
"disabledAriaLabel": "Tự động phê duyệt bị vô hiệu hóa - hãy chọn các tùy chọn trước",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "允许 Roo 自动执行操作而无需批准。只有在您完全信任 AI 并了解相关安全风险的情况下才启用这些设置。",
"enabled": "自动批准已启用",
"toggleAriaLabel": "切换自动批准",
"disabledAriaLabel": "自动批准已禁用 - 请先选择选项",
"readOnly": {

View file

@ -127,6 +127,7 @@
},
"autoApprove": {
"description": "允許 Roo 無需核准即執行操作。僅在您完全信任 AI 並了解相關安全風險時啟用這些設定。",
"enabled": "自動核准已啟用",
"toggleAriaLabel": "切換自動核准",
"disabledAriaLabel": "自動核准已停用 - 請先選取選項",
"readOnly": {