mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Adding a terminate task button to quit and restart
This commit is contained in:
Binary file not shown.
@@ -2,7 +2,7 @@
|
|||||||
"name": "roo-cline",
|
"name": "roo-cline",
|
||||||
"displayName": "Roo Cline",
|
"displayName": "Roo Cline",
|
||||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"icon": "assets/icons/icon.png",
|
"icon": "assets/icons/icon.png",
|
||||||
"galleryBanner": {
|
"galleryBanner": {
|
||||||
"color": "#617A91",
|
"color": "#617A91",
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
setClineAsk("resume_task")
|
setClineAsk("resume_task")
|
||||||
setEnableButtons(true)
|
setEnableButtons(true)
|
||||||
setPrimaryButtonText("Resume Task")
|
setPrimaryButtonText("Resume Task")
|
||||||
setSecondaryButtonText(undefined)
|
setSecondaryButtonText("Terminate")
|
||||||
setDidClickCancel(false) // special case where we reset the cancel button state
|
setDidClickCancel(false)
|
||||||
break
|
break
|
||||||
case "resume_completed_task":
|
case "resume_completed_task":
|
||||||
setTextAreaDisabled(false)
|
setTextAreaDisabled(false)
|
||||||
@@ -316,20 +316,18 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
switch (clineAsk) {
|
switch (clineAsk) {
|
||||||
case "api_req_failed":
|
case "api_req_failed":
|
||||||
case "mistake_limit_reached":
|
case "mistake_limit_reached":
|
||||||
|
case "resume_task":
|
||||||
startNewTask()
|
startNewTask()
|
||||||
break
|
break
|
||||||
case "command":
|
case "command":
|
||||||
case "tool":
|
case "tool":
|
||||||
case "browser_action_launch":
|
case "browser_action_launch":
|
||||||
// responds to the API with a "This operation failed" and lets it try again
|
|
||||||
vscode.postMessage({ type: "askResponse", askResponse: "noButtonClicked" })
|
vscode.postMessage({ type: "askResponse", askResponse: "noButtonClicked" })
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
setTextAreaDisabled(true)
|
setTextAreaDisabled(true)
|
||||||
setClineAsk(undefined)
|
setClineAsk(undefined)
|
||||||
setEnableButtons(false)
|
setEnableButtons(false)
|
||||||
// setPrimaryButtonText(undefined)
|
|
||||||
// setSecondaryButtonText(undefined)
|
|
||||||
disableAutoScrollRef.current = false
|
disableAutoScrollRef.current = false
|
||||||
}, [clineAsk, startNewTask, isStreaming])
|
}, [clineAsk, startNewTask, isStreaming])
|
||||||
|
|
||||||
|
|||||||
152
webview-ui/src/components/chat/__tests__/ChatView.test.tsx
Normal file
152
webview-ui/src/components/chat/__tests__/ChatView.test.tsx
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import { render, screen, act } from '@testing-library/react'
|
||||||
|
import userEvent from '@testing-library/user-event'
|
||||||
|
import { ExtensionStateContextType } from '../../../context/ExtensionStateContext'
|
||||||
|
import ChatView from '../ChatView'
|
||||||
|
import { vscode } from '../../../utils/vscode'
|
||||||
|
import * as ExtensionStateContext from '../../../context/ExtensionStateContext'
|
||||||
|
|
||||||
|
// Mock vscode
|
||||||
|
jest.mock('../../../utils/vscode', () => ({
|
||||||
|
vscode: {
|
||||||
|
postMessage: jest.fn()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Mock all components that use problematic dependencies
|
||||||
|
jest.mock('../../common/CodeBlock', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: () => <div data-testid="mock-code-block" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../../common/MarkdownBlock', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: () => <div data-testid="mock-markdown-block" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../BrowserSessionRow', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: () => <div data-testid="mock-browser-session-row" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Update ChatRow mock to capture props
|
||||||
|
let chatRowProps = null
|
||||||
|
jest.mock('../ChatRow', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: (props: any) => {
|
||||||
|
chatRowProps = props
|
||||||
|
return <div data-testid="mock-chat-row" />
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
// Mock Virtuoso component
|
||||||
|
jest.mock('react-virtuoso', () => ({
|
||||||
|
Virtuoso: ({ children }: any) => (
|
||||||
|
<div data-testid="mock-virtuoso">{children}</div>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Mock VS Code components
|
||||||
|
jest.mock('@vscode/webview-ui-toolkit/react', () => ({
|
||||||
|
VSCodeButton: ({ children, onClick }: any) => (
|
||||||
|
<button onClick={onClick}>{children}</button>
|
||||||
|
),
|
||||||
|
VSCodeProgressRing: () => <div data-testid="progress-ring" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('ChatView', () => {
|
||||||
|
const mockShowHistoryView = jest.fn()
|
||||||
|
const mockHideAnnouncement = jest.fn()
|
||||||
|
|
||||||
|
let mockState: ExtensionStateContextType
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
|
||||||
|
mockState = {
|
||||||
|
clineMessages: [],
|
||||||
|
apiConfiguration: {
|
||||||
|
apiProvider: 'anthropic',
|
||||||
|
apiModelId: 'claude-3-sonnet'
|
||||||
|
},
|
||||||
|
version: '1.0.0',
|
||||||
|
customInstructions: '',
|
||||||
|
alwaysAllowReadOnly: true,
|
||||||
|
alwaysAllowWrite: true,
|
||||||
|
alwaysAllowExecute: true,
|
||||||
|
openRouterModels: {},
|
||||||
|
didHydrateState: true,
|
||||||
|
showWelcome: false,
|
||||||
|
theme: 'dark',
|
||||||
|
filePaths: [],
|
||||||
|
taskHistory: [],
|
||||||
|
shouldShowAnnouncement: false,
|
||||||
|
uriScheme: 'vscode',
|
||||||
|
|
||||||
|
setAlwaysAllowReadOnly: jest.fn(),
|
||||||
|
setAlwaysAllowWrite: jest.fn(),
|
||||||
|
setCustomInstructions: jest.fn(),
|
||||||
|
setAlwaysAllowExecute: jest.fn(),
|
||||||
|
setApiConfiguration: jest.fn(),
|
||||||
|
setShowAnnouncement: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock the useExtensionState hook
|
||||||
|
jest.spyOn(ExtensionStateContext, 'useExtensionState').mockReturnValue(mockState)
|
||||||
|
})
|
||||||
|
|
||||||
|
const renderChatView = () => {
|
||||||
|
return render(
|
||||||
|
<ChatView
|
||||||
|
isHidden={false}
|
||||||
|
showAnnouncement={false}
|
||||||
|
hideAnnouncement={mockHideAnnouncement}
|
||||||
|
showHistoryView={mockShowHistoryView}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Streaming State', () => {
|
||||||
|
it('should show cancel button while streaming', () => {
|
||||||
|
mockState.clineMessages = [
|
||||||
|
{
|
||||||
|
type: 'say',
|
||||||
|
partial: true,
|
||||||
|
ts: Date.now(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
renderChatView()
|
||||||
|
|
||||||
|
const buttons = screen.queryAllByRole('button')
|
||||||
|
expect(buttons.length).toBeGreaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should show terminate button when task is paused', () => {
|
||||||
|
mockState.clineMessages = [
|
||||||
|
{
|
||||||
|
type: 'ask',
|
||||||
|
ask: 'resume_task',
|
||||||
|
ts: Date.now(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
renderChatView()
|
||||||
|
|
||||||
|
const buttons = screen.queryAllByRole('button')
|
||||||
|
expect(buttons.length).toBeGreaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should show retry button when API error occurs', () => {
|
||||||
|
mockState.clineMessages = [
|
||||||
|
{
|
||||||
|
type: 'say',
|
||||||
|
say: 'error',
|
||||||
|
ts: Date.now(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
renderChatView()
|
||||||
|
|
||||||
|
const buttons = screen.queryAllByRole('button')
|
||||||
|
expect(buttons.length).toBeGreaterThan(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user