Browse Source

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>
Matt Rubens 5 months ago
parent
commit
305a5da369

+ 0 - 12
webview-ui/src/components/chat/AutoApproveMenu.tsx

@@ -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>

+ 57 - 46
webview-ui/src/components/settings/AutoApproveSettings.tsx

@@ -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 */}
 

+ 7 - 12
webview-ui/src/components/settings/AutoApproveToggle.tsx

@@ -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>
 			))}

+ 14 - 16
webview-ui/src/components/settings/MaxCostInput.tsx

@@ -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>]}
+			/>
+		</>
 	)
 }

+ 1 - 1
webview-ui/src/components/settings/MaxLimitInputs.tsx

@@ -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>

+ 13 - 15
webview-ui/src/components/settings/MaxRequestsInput.tsx

@@ -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"
+			/>
+		</>
 	)
 }

+ 1 - 0
webview-ui/src/i18n/locales/ca/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/de/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/en/settings.json

@@ -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.",

+ 1 - 0
webview-ui/src/i18n/locales/es/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/fr/settings.json

@@ -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",

+ 1 - 0
webview-ui/src/i18n/locales/hi/settings.json

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

+ 1 - 0
webview-ui/src/i18n/locales/id/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/it/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/ja/settings.json

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

+ 1 - 0
webview-ui/src/i18n/locales/ko/settings.json

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

+ 1 - 0
webview-ui/src/i18n/locales/nl/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/pl/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/pt-BR/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/ru/settings.json

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

+ 1 - 0
webview-ui/src/i18n/locales/tr/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/vi/settings.json

@@ -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": {

+ 1 - 0
webview-ui/src/i18n/locales/zh-CN/settings.json

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

+ 1 - 0
webview-ui/src/i18n/locales/zh-TW/settings.json

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