Browse Source

ux: improve auto-approve timer visibility in follow-up suggestions (#10048)

Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: Roo Code <[email protected]>
Bruno Bergher 1 month ago
parent
commit
495b5c6c6e

+ 16 - 9
webview-ui/src/components/chat/FollowUpSuggest.tsx

@@ -1,11 +1,12 @@
 import { useCallback, useEffect, useState } from "react"
-import { ClipboardCopy } from "lucide-react"
+import { ClipboardCopy, Timer } from "lucide-react"
 
 import { Button, StandardTooltip } from "@/components/ui"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { useExtensionState } from "@src/context/ExtensionStateContext"
 import { SuggestionItem } from "@roo-code/types"
+import { cn } from "@/lib/utils"
 
 const DEFAULT_FOLLOWUP_TIMEOUT_MS = 60000
 const COUNTDOWN_INTERVAL_MS = 1000
@@ -111,18 +112,24 @@ export const FollowUpSuggest = ({
 					<div key={`${suggestion.answer}-${ts}`} className="w-full relative group">
 						<Button
 							variant="outline"
-							className="text-left whitespace-normal break-words w-full h-auto px-3 py-2 justify-start pr-8 rounded-xl"
+							className={cn(
+								"text-left whitespace-normal break-words w-full h-auto px-3 py-2 justify-start pr-8 rounded-xl",
+								isFirstSuggestion &&
+									countdown !== null &&
+									!suggestionSelected &&
+									!isAnswered &&
+									"border-vscode-foreground/60 rounded-b-none -mb-1",
+							)}
 							onClick={(event) => handleSuggestionClick(suggestion, event)}
 							aria-label={suggestion.answer}>
 							{suggestion.answer}
-							{isFirstSuggestion && countdown !== null && !suggestionSelected && !isAnswered && (
-								<span
-									className="ml-2 px-1.5 py-0.5 text-xs rounded-full bg-vscode-badge-background text-vscode-badge-foreground"
-									title={t("chat:followUpSuggest.autoSelectCountdown", { count: countdown })}>
-									{t("chat:followUpSuggest.countdownDisplay", { count: countdown })}
-								</span>
-							)}
 						</Button>
+						{isFirstSuggestion && countdown !== null && !suggestionSelected && !isAnswered && (
+							<p className="rounded-b-xl border-1 border-t-0 border-vscode-foreground/60 text-vscode-descriptionForeground text-xs m-0 mt-1 px-3 pt-2 pb-2">
+								<Timer className="size-3 inline-block -mt-0.5 mr-1 animate-pulse" />
+								{t("chat:followUpSuggest.timerPrefix", { seconds: countdown })}
+							</p>
+						)}
 						{suggestion.mode && (
 							<div className="absolute bottom-0 right-0 text-[10px] bg-vscode-badge-background text-vscode-badge-foreground px-1 py-0.5 border border-vscode-badge-background flex items-center gap-0.5">
 								<span className="codicon codicon-arrow-right" style={{ fontSize: "8px" }} />

+ 6 - 4
webview-ui/src/components/chat/__tests__/FollowUpSuggest.spec.tsx

@@ -12,12 +12,13 @@ vi.mock("@src/i18n/TranslationContext", () => ({
 			if (key === "chat:followUpSuggest.countdownDisplay" && options?.count !== undefined) {
 				return `${options.count}s`
 			}
-			if (key === "chat:followUpSuggest.autoSelectCountdown" && options?.count !== undefined) {
-				return `Auto-selecting in ${options.count} seconds`
-			}
 			if (key === "chat:followUpSuggest.copyToInput") {
 				return "Copy to input"
 			}
+			if (key === "chat:followUpSuggest.timerPrefix" && options?.seconds !== undefined) {
+				return "Auto-approve enabled. Selecting in " + options.seconds + "s…"
+			}
+
 			return key
 		},
 	}),
@@ -93,8 +94,9 @@ describe("FollowUpSuggest", () => {
 			defaultTestState,
 		)
 
-		// Should show initial countdown (3 seconds)
+		// Should countdown and mention
 		expect(screen.getByText(/3s/)).toBeInTheDocument()
+		expect(screen.getByText(/Selecting in 3s/)).toBeInTheDocument()
 	})
 
 	it("should not display countdown timer when isAnswered is true", () => {

+ 1 - 2
webview-ui/src/i18n/locales/ca/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Copiar a l'entrada (o Shift + clic)",
-		"autoSelectCountdown": "Selecció automàtica en {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Aprovació automàtica habilitada. Seleccionant en {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} Llançat",

+ 1 - 2
webview-ui/src/i18n/locales/de/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "In Eingabefeld kopieren (oder Shift + Klick)",
-		"autoSelectCountdown": "Automatische Auswahl in {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Automatische Genehmigung aktiviert. Wähle in {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} veröffentlicht",

+ 1 - 2
webview-ui/src/i18n/locales/en/chat.json

@@ -341,8 +341,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Copy to input (same as shift + click)",
-		"autoSelectCountdown": "Auto-selecting in {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Auto-approve enabled. Selecting in {{seconds}}s…"
 	},
 	"browser": {
 		"session": "Browser Session",

+ 1 - 2
webview-ui/src/i18n/locales/es/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Copiar a la entrada (o Shift + clic)",
-		"autoSelectCountdown": "Selección automática en {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Aprobación automática habilitada. Seleccionando en {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} publicado",

+ 1 - 2
webview-ui/src/i18n/locales/fr/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Copier vers l'entrée (ou Shift + clic)",
-		"autoSelectCountdown": "Sélection automatique dans {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Approbation automatique activée. Sélection dans {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} est sortie",

+ 1 - 2
webview-ui/src/i18n/locales/hi/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "इनपुट में कॉपी करें (या Shift + क्लिक)",
-		"autoSelectCountdown": "{{count}}s में स्वचालित रूप से चयन हो रहा है",
-		"countdownDisplay": "{{count}}सेकंड"
+		"timerPrefix": "ऑटो-अनुमोदन सक्षम है। {{seconds}}s में चयन किया जा रहा है…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} रिलीज़ हुआ",

+ 1 - 2
webview-ui/src/i18n/locales/id/chat.json

@@ -347,8 +347,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Salin ke input (sama dengan shift + klik)",
-		"autoSelectCountdown": "Pemilihan otomatis dalam {{count}}dtk",
-		"countdownDisplay": "{{count}}dtk"
+		"timerPrefix": "Persetujuan otomatis diaktifkan. Memilih dalam {{seconds}}s…"
 	},
 	"browser": {
 		"session": "Sesi Browser",

+ 1 - 2
webview-ui/src/i18n/locales/it/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Copia nell'input (o Shift + clic)",
-		"autoSelectCountdown": "Selezione automatica in {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Approvazione automatica abilitata. Selezione tra {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Rilasciato Roo Code {{version}}",

+ 1 - 2
webview-ui/src/i18n/locales/ja/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "入力欄にコピー(またはShift + クリック)",
-		"autoSelectCountdown": "{{count}}秒後に自動選択します",
-		"countdownDisplay": "{{count}}秒"
+		"timerPrefix": "自動承認が有効です。{{seconds}}秒後に選択中…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} リリース",

+ 1 - 2
webview-ui/src/i18n/locales/ko/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "입력창에 복사 (또는 Shift + 클릭)",
-		"autoSelectCountdown": "{{count}}초 후 자동 선택",
-		"countdownDisplay": "{{count}}초"
+		"timerPrefix": "자동 승인 활성화됨. {{seconds}}초 후 선택 중…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} 출시",

+ 1 - 2
webview-ui/src/i18n/locales/nl/chat.json

@@ -326,8 +326,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Kopiëren naar invoer (zelfde als shift + klik)",
-		"autoSelectCountdown": "Automatische selectie in {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Automatisch goedkeuren ingeschakeld. Selecteren in {{seconds}}s…"
 	},
 	"browser": {
 		"session": "Browsersessie",

+ 1 - 2
webview-ui/src/i18n/locales/pl/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Kopiuj do pola wprowadzania (lub Shift + kliknięcie)",
-		"autoSelectCountdown": "Automatyczny wybór za {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Automatyczne zatwierdzanie włączone. Zaznaczanie za {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} wydany",

+ 1 - 2
webview-ui/src/i18n/locales/pt-BR/chat.json

@@ -303,8 +303,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Copiar para entrada (ou Shift + clique)",
-		"autoSelectCountdown": "Seleção automática em {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Aprovação automática ativada. Selecionando em {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} Lançado",

+ 1 - 2
webview-ui/src/i18n/locales/ru/chat.json

@@ -327,8 +327,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Скопировать во ввод (то же, что shift + клик)",
-		"autoSelectCountdown": "Автовыбор через {{count}}с",
-		"countdownDisplay": "{{count}}с"
+		"timerPrefix": "Автоматическое одобрение включено. Выбор через {{seconds}}s…"
 	},
 	"browser": {
 		"session": "Сеанс браузера",

+ 1 - 2
webview-ui/src/i18n/locales/tr/chat.json

@@ -304,8 +304,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Giriş alanına kopyala (veya Shift + tıklama)",
-		"autoSelectCountdown": "{{count}}s içinde otomatik seçilecek",
-		"countdownDisplay": "{{count}}sn"
+		"timerPrefix": "Otomatik onay etkinleştirildi. {{seconds}}s içinde seçim yapılıyor…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} Yayınlandı",

+ 1 - 2
webview-ui/src/i18n/locales/vi/chat.json

@@ -304,8 +304,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "Sao chép vào ô nhập liệu (hoặc Shift + nhấp chuột)",
-		"autoSelectCountdown": "Tự động chọn sau {{count}}s",
-		"countdownDisplay": "{{count}}s"
+		"timerPrefix": "Phê duyệt tự động được bật. Chọn trong {{seconds}}s…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} Đã phát hành",

+ 1 - 2
webview-ui/src/i18n/locales/zh-CN/chat.json

@@ -304,8 +304,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "复制到输入框(或按住Shift点击)",
-		"autoSelectCountdown": "{{count}}秒后自动选择",
-		"countdownDisplay": "{{count}}秒"
+		"timerPrefix": "自动批准已启用。{{seconds}}秒后选择中…"
 	},
 	"announcement": {
 		"title": "Roo Code {{version}} 已发布",

+ 1 - 2
webview-ui/src/i18n/locales/zh-TW/chat.json

@@ -345,8 +345,7 @@
 	},
 	"followUpSuggest": {
 		"copyToInput": "複製到輸入框 (或按住 Shift 並點選)",
-		"autoSelectCountdown": "{{count}} 秒後自動選擇",
-		"countdownDisplay": "{{count}} 秒"
+		"timerPrefix": "自動批准已啟用。{{seconds}}秒後選擇中…"
 	},
 	"browser": {
 		"session": "瀏覽器會話",