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 <roomote@roocode.com>
This commit is contained in:
Bruno Bergher 2025-12-12 14:51:00 +00:00 committed by GitHub
parent f97b5155ac
commit 495b5c6c6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 40 additions and 49 deletions

View file

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

View file

@ -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", () => {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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