mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Fixes to the auto approve menu
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useCallback, useState } from "react"
|
||||
import { useExtensionState } from "../../context/ExtensionStateContext"
|
||||
import { vscode } from "../../utils/vscode"
|
||||
|
||||
interface AutoApproveAction {
|
||||
id: string
|
||||
@@ -50,7 +51,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
||||
},
|
||||
{
|
||||
id: "executeCommands",
|
||||
label: "Execute safe commands",
|
||||
label: "Execute approved commands",
|
||||
shortName: "Commands",
|
||||
enabled: alwaysAllowExecute ?? false,
|
||||
description:
|
||||
@@ -89,12 +90,41 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
||||
.join(", ")
|
||||
|
||||
// Individual checkbox handlers - each one only updates its own state
|
||||
const handleReadOnlyChange = useCallback(() => setAlwaysAllowReadOnly(!(alwaysAllowReadOnly ?? false)), [alwaysAllowReadOnly, setAlwaysAllowReadOnly])
|
||||
const handleWriteChange = useCallback(() => setAlwaysAllowWrite(!(alwaysAllowWrite ?? false)), [alwaysAllowWrite, setAlwaysAllowWrite])
|
||||
const handleExecuteChange = useCallback(() => setAlwaysAllowExecute(!(alwaysAllowExecute ?? false)), [alwaysAllowExecute, setAlwaysAllowExecute])
|
||||
const handleBrowserChange = useCallback(() => setAlwaysAllowBrowser(!(alwaysAllowBrowser ?? false)), [alwaysAllowBrowser, setAlwaysAllowBrowser])
|
||||
const handleMcpChange = useCallback(() => setAlwaysAllowMcp(!(alwaysAllowMcp ?? false)), [alwaysAllowMcp, setAlwaysAllowMcp])
|
||||
const handleRetryChange = useCallback(() => setAlwaysApproveResubmit(!(alwaysApproveResubmit ?? false)), [alwaysApproveResubmit, setAlwaysApproveResubmit])
|
||||
const handleReadOnlyChange = useCallback(() => {
|
||||
const newValue = !(alwaysAllowReadOnly ?? false)
|
||||
setAlwaysAllowReadOnly(newValue)
|
||||
vscode.postMessage({ type: "alwaysAllowReadOnly", bool: newValue })
|
||||
}, [alwaysAllowReadOnly, setAlwaysAllowReadOnly])
|
||||
|
||||
const handleWriteChange = useCallback(() => {
|
||||
const newValue = !(alwaysAllowWrite ?? false)
|
||||
setAlwaysAllowWrite(newValue)
|
||||
vscode.postMessage({ type: "alwaysAllowWrite", bool: newValue })
|
||||
}, [alwaysAllowWrite, setAlwaysAllowWrite])
|
||||
|
||||
const handleExecuteChange = useCallback(() => {
|
||||
const newValue = !(alwaysAllowExecute ?? false)
|
||||
setAlwaysAllowExecute(newValue)
|
||||
vscode.postMessage({ type: "alwaysAllowExecute", bool: newValue })
|
||||
}, [alwaysAllowExecute, setAlwaysAllowExecute])
|
||||
|
||||
const handleBrowserChange = useCallback(() => {
|
||||
const newValue = !(alwaysAllowBrowser ?? false)
|
||||
setAlwaysAllowBrowser(newValue)
|
||||
vscode.postMessage({ type: "alwaysAllowBrowser", bool: newValue })
|
||||
}, [alwaysAllowBrowser, setAlwaysAllowBrowser])
|
||||
|
||||
const handleMcpChange = useCallback(() => {
|
||||
const newValue = !(alwaysAllowMcp ?? false)
|
||||
setAlwaysAllowMcp(newValue)
|
||||
vscode.postMessage({ type: "alwaysAllowMcp", bool: newValue })
|
||||
}, [alwaysAllowMcp, setAlwaysAllowMcp])
|
||||
|
||||
const handleRetryChange = useCallback(() => {
|
||||
const newValue = !(alwaysApproveResubmit ?? false)
|
||||
setAlwaysApproveResubmit(newValue)
|
||||
vscode.postMessage({ type: "alwaysApproveResubmit", bool: newValue })
|
||||
}, [alwaysApproveResubmit, setAlwaysApproveResubmit])
|
||||
|
||||
// Map action IDs to their specific handlers
|
||||
const actionHandlers: Record<AutoApproveAction['id'], () => void> = {
|
||||
@@ -129,7 +159,11 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<VSCodeCheckbox
|
||||
checked={autoApprovalEnabled ?? false}
|
||||
onChange={() => setAutoApprovalEnabled(!(autoApprovalEnabled ?? false))}
|
||||
onChange={() => {
|
||||
const newValue = !(autoApprovalEnabled ?? false)
|
||||
setAutoApprovalEnabled(newValue)
|
||||
vscode.postMessage({ type: "autoApprovalEnabled", bool: newValue })
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{
|
||||
|
||||
@@ -109,7 +109,7 @@ describe("AutoApproveMenu", () => {
|
||||
// Verify menu items are visible
|
||||
expect(screen.getByText("Read files and directories")).toBeInTheDocument()
|
||||
expect(screen.getByText("Edit files")).toBeInTheDocument()
|
||||
expect(screen.getByText("Execute safe commands")).toBeInTheDocument()
|
||||
expect(screen.getByText("Execute approved commands")).toBeInTheDocument()
|
||||
expect(screen.getByText("Use the browser")).toBeInTheDocument()
|
||||
expect(screen.getByText("Use MCP servers")).toBeInTheDocument()
|
||||
expect(screen.getByText("Retry failed requests")).toBeInTheDocument()
|
||||
@@ -139,7 +139,7 @@ describe("AutoApproveMenu", () => {
|
||||
expect(defaultMockState.setAlwaysAllowWrite).toHaveBeenCalledWith(true)
|
||||
|
||||
// Click execute commands checkbox
|
||||
fireEvent.click(screen.getByText("Execute safe commands"))
|
||||
fireEvent.click(screen.getByText("Execute approved commands"))
|
||||
expect(defaultMockState.setAlwaysAllowExecute).toHaveBeenCalledWith(true)
|
||||
})
|
||||
|
||||
|
||||
@@ -144,104 +144,6 @@ describe('ChatView - Auto Approval Tests', () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it('defaults autoApprovalEnabled to true if any individual auto-approval flags are true', async () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ChatView
|
||||
isHidden={false}
|
||||
showAnnouncement={false}
|
||||
hideAnnouncement={() => {}}
|
||||
showHistoryView={() => {}}
|
||||
/>
|
||||
</ExtensionStateContextProvider>
|
||||
)
|
||||
|
||||
// Test cases with different individual flags
|
||||
const testCases = [
|
||||
{ alwaysAllowBrowser: true },
|
||||
{ alwaysAllowReadOnly: true },
|
||||
{ alwaysAllowWrite: true },
|
||||
{ alwaysAllowExecute: true },
|
||||
{ alwaysAllowMcp: true }
|
||||
]
|
||||
|
||||
for (const flags of testCases) {
|
||||
// Reset state
|
||||
mockPostMessage({
|
||||
...flags,
|
||||
clineMessages: []
|
||||
})
|
||||
|
||||
// Send an action that should be auto-approved
|
||||
mockPostMessage({
|
||||
...flags,
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
say: 'task',
|
||||
ts: Date.now() - 2000,
|
||||
text: 'Initial task'
|
||||
},
|
||||
{
|
||||
type: 'ask',
|
||||
ask: flags.alwaysAllowBrowser ? 'browser_action_launch' :
|
||||
flags.alwaysAllowReadOnly ? 'tool' :
|
||||
flags.alwaysAllowWrite ? 'tool' :
|
||||
flags.alwaysAllowExecute ? 'command' :
|
||||
'use_mcp_server',
|
||||
ts: Date.now(),
|
||||
text: flags.alwaysAllowBrowser ? JSON.stringify({ action: 'launch', url: 'http://example.com' }) :
|
||||
flags.alwaysAllowReadOnly ? JSON.stringify({ tool: 'readFile', path: 'test.txt' }) :
|
||||
flags.alwaysAllowWrite ? JSON.stringify({ tool: 'editedExistingFile', path: 'test.txt' }) :
|
||||
flags.alwaysAllowExecute ? 'npm test' :
|
||||
JSON.stringify({ type: 'use_mcp_tool', serverName: 'test', toolName: 'test' }),
|
||||
partial: false
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// Wait for auto-approval
|
||||
await waitFor(() => {
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: 'askResponse',
|
||||
askResponse: 'yesButtonClicked'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Verify no auto-approval when no flags are true
|
||||
jest.clearAllMocks()
|
||||
mockPostMessage({
|
||||
alwaysAllowBrowser: false,
|
||||
alwaysAllowReadOnly: false,
|
||||
alwaysAllowWrite: false,
|
||||
alwaysAllowExecute: false,
|
||||
alwaysAllowMcp: false,
|
||||
clineMessages: [
|
||||
{
|
||||
type: 'say',
|
||||
say: 'task',
|
||||
ts: Date.now() - 2000,
|
||||
text: 'Initial task'
|
||||
},
|
||||
{
|
||||
type: 'ask',
|
||||
ask: 'browser_action_launch',
|
||||
ts: Date.now(),
|
||||
text: JSON.stringify({ action: 'launch', url: 'http://example.com' }),
|
||||
partial: false
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// Wait a bit to ensure no auto-approval happens
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
expect(vscode.postMessage).not.toHaveBeenCalledWith({
|
||||
type: 'askResponse',
|
||||
askResponse: 'yesButtonClicked'
|
||||
})
|
||||
})
|
||||
|
||||
it('does not auto-approve any actions when autoApprovalEnabled is false', () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
|
||||
@@ -124,16 +124,6 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
||||
switch (message.type) {
|
||||
case "state": {
|
||||
const newState = message.state!
|
||||
// Set autoApprovalEnabled to true if undefined and any individual flag is true
|
||||
if (newState.autoApprovalEnabled === undefined) {
|
||||
newState.autoApprovalEnabled = !!(
|
||||
newState.alwaysAllowBrowser ||
|
||||
newState.alwaysAllowReadOnly ||
|
||||
newState.alwaysAllowWrite ||
|
||||
newState.alwaysAllowExecute ||
|
||||
newState.alwaysAllowMcp ||
|
||||
newState.alwaysApproveResubmit)
|
||||
}
|
||||
setState(prevState => ({
|
||||
...prevState,
|
||||
...newState
|
||||
|
||||
Reference in New Issue
Block a user