mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
feat: add keyboard shortcuts for auto-approve selection
- Add Alt+1 through Alt+0 keyboard shortcuts to toggle auto-approve options - Display keyboard shortcuts in tooltips for each option - Create AutoApproveKeyboardShortcuts component to handle global keyboard events
This commit is contained in:
parent
e19492fb57
commit
67d9d14549
3 changed files with 164 additions and 24 deletions
121
webview-ui/src/components/chat/AutoApproveKeyboardShortcuts.tsx
Normal file
121
webview-ui/src/components/chat/AutoApproveKeyboardShortcuts.tsx
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
import { useEffect, useCallback, useMemo } from "react"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { AutoApproveSetting } from "../settings/AutoApproveToggle"
|
||||
import { useAutoApprovalToggles } from "@src/hooks/useAutoApprovalToggles"
|
||||
|
||||
// Keyboard shortcuts mapping for auto-approve options
|
||||
const KEYBOARD_SHORTCUTS: Record<string, AutoApproveSetting> = {
|
||||
"1": "alwaysAllowReadOnly",
|
||||
"2": "alwaysAllowWrite",
|
||||
"3": "alwaysAllowBrowser",
|
||||
"4": "alwaysAllowExecute",
|
||||
"5": "alwaysAllowMcp",
|
||||
"6": "alwaysAllowModeSwitch",
|
||||
"7": "alwaysAllowSubtasks",
|
||||
"8": "alwaysAllowFollowupQuestions",
|
||||
"9": "alwaysAllowUpdateTodoList",
|
||||
"0": "alwaysApproveResubmit",
|
||||
}
|
||||
|
||||
export const AutoApproveKeyboardShortcuts = () => {
|
||||
const {
|
||||
setAlwaysAllowReadOnly,
|
||||
setAlwaysAllowWrite,
|
||||
setAlwaysAllowExecute,
|
||||
setAlwaysAllowBrowser,
|
||||
setAlwaysAllowMcp,
|
||||
setAlwaysAllowModeSwitch,
|
||||
setAlwaysAllowSubtasks,
|
||||
setAlwaysApproveResubmit,
|
||||
setAlwaysAllowFollowupQuestions,
|
||||
setAlwaysAllowUpdateTodoList,
|
||||
alwaysApproveResubmit,
|
||||
} = useExtensionState()
|
||||
|
||||
const baseToggles = useAutoApprovalToggles()
|
||||
const toggles = useMemo(
|
||||
() => ({
|
||||
...baseToggles,
|
||||
alwaysApproveResubmit,
|
||||
}),
|
||||
[baseToggles, alwaysApproveResubmit],
|
||||
)
|
||||
|
||||
const handleToggle = useCallback(
|
||||
(key: AutoApproveSetting) => {
|
||||
const currentValue = toggles[key]
|
||||
const newValue = !currentValue
|
||||
|
||||
// Send message to extension
|
||||
vscode.postMessage({ type: key, bool: newValue })
|
||||
|
||||
// Update local state
|
||||
switch (key) {
|
||||
case "alwaysAllowReadOnly":
|
||||
setAlwaysAllowReadOnly(newValue)
|
||||
break
|
||||
case "alwaysAllowWrite":
|
||||
setAlwaysAllowWrite(newValue)
|
||||
break
|
||||
case "alwaysAllowExecute":
|
||||
setAlwaysAllowExecute(newValue)
|
||||
break
|
||||
case "alwaysAllowBrowser":
|
||||
setAlwaysAllowBrowser(newValue)
|
||||
break
|
||||
case "alwaysAllowMcp":
|
||||
setAlwaysAllowMcp(newValue)
|
||||
break
|
||||
case "alwaysAllowModeSwitch":
|
||||
setAlwaysAllowModeSwitch(newValue)
|
||||
break
|
||||
case "alwaysAllowSubtasks":
|
||||
setAlwaysAllowSubtasks(newValue)
|
||||
break
|
||||
case "alwaysApproveResubmit":
|
||||
setAlwaysApproveResubmit(newValue)
|
||||
break
|
||||
case "alwaysAllowFollowupQuestions":
|
||||
setAlwaysAllowFollowupQuestions(newValue)
|
||||
break
|
||||
case "alwaysAllowUpdateTodoList":
|
||||
setAlwaysAllowUpdateTodoList(newValue)
|
||||
break
|
||||
}
|
||||
},
|
||||
[
|
||||
toggles,
|
||||
setAlwaysAllowReadOnly,
|
||||
setAlwaysAllowWrite,
|
||||
setAlwaysAllowExecute,
|
||||
setAlwaysAllowBrowser,
|
||||
setAlwaysAllowMcp,
|
||||
setAlwaysAllowModeSwitch,
|
||||
setAlwaysAllowSubtasks,
|
||||
setAlwaysApproveResubmit,
|
||||
setAlwaysAllowFollowupQuestions,
|
||||
setAlwaysAllowUpdateTodoList,
|
||||
],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
// Check if Alt/Option key is pressed along with a number key
|
||||
if (event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
|
||||
const shortcut = KEYBOARD_SHORTCUTS[event.key]
|
||||
if (shortcut) {
|
||||
event.preventDefault()
|
||||
handleToggle(shortcut)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown)
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyDown)
|
||||
}
|
||||
}, [handleToggle])
|
||||
|
||||
return null // This component doesn't render anything
|
||||
}
|
||||
|
|
@ -22,6 +22,20 @@ type AutoApproveToggleDropdownProps = AutoApproveToggles & {
|
|||
onToggle: (key: AutoApproveSetting, value: boolean) => void
|
||||
}
|
||||
|
||||
// Keyboard shortcuts mapping
|
||||
const KEYBOARD_SHORTCUTS: Record<AutoApproveSetting, string> = {
|
||||
alwaysAllowReadOnly: "Alt+1",
|
||||
alwaysAllowWrite: "Alt+2",
|
||||
alwaysAllowBrowser: "Alt+3",
|
||||
alwaysAllowExecute: "Alt+4",
|
||||
alwaysAllowMcp: "Alt+5",
|
||||
alwaysAllowModeSwitch: "Alt+6",
|
||||
alwaysAllowSubtasks: "Alt+7",
|
||||
alwaysAllowFollowupQuestions: "Alt+8",
|
||||
alwaysAllowUpdateTodoList: "Alt+9",
|
||||
alwaysApproveResubmit: "Alt+0",
|
||||
}
|
||||
|
||||
export const AutoApproveToggleDropdown = ({ onToggle, ...props }: AutoApproveToggleDropdownProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
|
|
@ -37,32 +51,35 @@ export const AutoApproveToggleDropdown = ({ onToggle, ...props }: AutoApproveTog
|
|||
labelKey,
|
||||
icon,
|
||||
testId,
|
||||
}: (typeof autoApproveSettingsConfig)[AutoApproveSetting]) => (
|
||||
<StandardTooltip key={key} content={t(descriptionKey || "")}>
|
||||
<button
|
||||
onClick={() => onToggle(key, !props[key])}
|
||||
aria-label={t(labelKey)}
|
||||
aria-pressed={!!props[key]}
|
||||
data-testid={testId}
|
||||
className={cn(
|
||||
"w-full flex items-center gap-2 px-2 py-1.5 rounded text-xs text-left",
|
||||
"transition-colors hover:bg-vscode-list-hoverBackground",
|
||||
props[key]
|
||||
? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground"
|
||||
: "opacity-70",
|
||||
)}>
|
||||
<span className={cn("codicon", `codicon-${icon}`, "text-sm flex-shrink-0")} />
|
||||
<span className="flex-1 truncate">{t(labelKey)}</span>
|
||||
<span
|
||||
}: (typeof autoApproveSettingsConfig)[AutoApproveSetting]) => {
|
||||
const tooltipContent = `${t(descriptionKey || "")} (${KEYBOARD_SHORTCUTS[key]})`
|
||||
return (
|
||||
<StandardTooltip key={key} content={tooltipContent}>
|
||||
<button
|
||||
onClick={() => onToggle(key, !props[key])}
|
||||
aria-label={t(labelKey)}
|
||||
aria-pressed={!!props[key]}
|
||||
data-testid={testId}
|
||||
className={cn(
|
||||
"text-[10px] px-1 rounded",
|
||||
props[key] ? "bg-vscode-badge-background text-vscode-badge-foreground" : "",
|
||||
"w-full flex items-center gap-2 px-2 py-1.5 rounded text-xs text-left",
|
||||
"transition-colors hover:bg-vscode-list-hoverBackground",
|
||||
props[key]
|
||||
? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground"
|
||||
: "opacity-70",
|
||||
)}>
|
||||
{props[key] ? "✓" : ""}
|
||||
</span>
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
)
|
||||
<span className={cn("codicon", `codicon-${icon}`, "text-sm flex-shrink-0")} />
|
||||
<span className="flex-1 truncate">{t(labelKey)}</span>
|
||||
<span
|
||||
className={cn(
|
||||
"text-[10px] px-1 rounded",
|
||||
props[key] ? "bg-vscode-badge-background text-vscode-badge-foreground" : "",
|
||||
)}>
|
||||
{props[key] ? "✓" : ""}
|
||||
</span>
|
||||
</button>
|
||||
</StandardTooltip>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import ChatRow from "./ChatRow"
|
|||
import ChatTextArea from "./ChatTextArea"
|
||||
import TaskHeader from "./TaskHeader"
|
||||
import AutoApproveMenu from "./AutoApproveMenu"
|
||||
import { AutoApproveKeyboardShortcuts } from "./AutoApproveKeyboardShortcuts"
|
||||
import SystemPromptWarning from "./SystemPromptWarning"
|
||||
import ProfileViolationWarning from "./ProfileViolationWarning"
|
||||
import { CheckpointWarning } from "./CheckpointWarning"
|
||||
|
|
@ -1793,6 +1794,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
<div
|
||||
data-testid="chat-view"
|
||||
className={isHidden ? "hidden" : "fixed top-0 left-0 right-0 bottom-0 flex flex-col overflow-hidden"}>
|
||||
<AutoApproveKeyboardShortcuts />
|
||||
{(showAnnouncement || showAnnouncementModal) && (
|
||||
<Announcement
|
||||
hideAnnouncement={() => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue