diff --git a/CHANGELOG.md b/CHANGELOG.md index 69337d08a..44b80bd04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## What's new in 4.0.31 +### Improvements + +- **RovoDev**: Collapsed completed tool call results in the thinking drawer for a more compact chat view. Users can still expand the drawer to see details. + ### Bug Fixes - **RovoDev**: Hid stack traces, stderr, and log details from external users while preserving them for Atlassian users. diff --git a/src/rovo-dev/ui/RovoDev.css b/src/rovo-dev/ui/RovoDev.css index 29a3a078b..81d829553 100644 --- a/src/rovo-dev/ui/RovoDev.css +++ b/src/rovo-dev/ui/RovoDev.css @@ -302,6 +302,21 @@ body { word-break: break-all; } +.tool-return-collapsed { + border: none; + padding: 2px 6px; + margin-bottom: 2px; + gap: 6px; +} + +.tool-return-collapsed-text { + font-size: 12px; + color: var(--vscode-input-placeholderForeground); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + .tool-return-bash-command { pre { margin: 0; diff --git a/src/rovo-dev/ui/common/common.tsx b/src/rovo-dev/ui/common/common.tsx index 8afd17014..46c710137 100644 --- a/src/rovo-dev/ui/common/common.tsx +++ b/src/rovo-dev/ui/common/common.tsx @@ -215,6 +215,7 @@ export const renderChatHistory = ( retryAfterError: () => void, onError: (error: Error, errorMessage: string) => void, isAtlassianUser?: boolean, + collapsedToolReturns?: boolean, ) => { switch (msg.event_kind) { case 'tool-return': @@ -223,7 +224,15 @@ export const renderChatHistory = ( if (message.todoData) { return ; } - return ; + return ( + + ); }); case '_RovoDevDialog': let customButton: { text: string; onClick: () => void } | undefined = undefined; diff --git a/src/rovo-dev/ui/messaging/MessageDrawer.tsx b/src/rovo-dev/ui/messaging/MessageDrawer.tsx index 41a44461c..7e65ff286 100644 --- a/src/rovo-dev/ui/messaging/MessageDrawer.tsx +++ b/src/rovo-dev/ui/messaging/MessageDrawer.tsx @@ -80,6 +80,7 @@ export const MessageDrawer: React.FC = ({ retryPromptAfterError, onError, isAtlassianUser, + true, // collapse tool returns for compact display ), )} diff --git a/src/rovo-dev/ui/tools/ToolReturnItem.test.tsx b/src/rovo-dev/ui/tools/ToolReturnItem.test.tsx index c0fef7d1a..b7fbdf546 100644 --- a/src/rovo-dev/ui/tools/ToolReturnItem.test.tsx +++ b/src/rovo-dev/ui/tools/ToolReturnItem.test.tsx @@ -124,4 +124,65 @@ describe('ToolReturnParsedItem', () => { render(); }).not.toThrow(); }); + + test('renders collapsed view with content and title', () => { + const msg: ToolReturnParseResult = { + content: 'Replaced code', + title: 'myFile.ts', + type: 'modify', + filePath: '/path/to/myFile.ts', + }; + + const { getByText, container } = render( + , + ); + + expect(container.querySelector('.tool-return-collapsed')).toBeTruthy(); + expect(getByText('Replaced code — myFile.ts')).toBeTruthy(); + }); + + test('renders collapsed view with content only (no title)', () => { + const msg: ToolReturnParseResult = { + content: 'Searched files', + type: 'open', + }; + + const { getByText, container } = render( + , + ); + + expect(container.querySelector('.tool-return-collapsed')).toBeTruthy(); + expect(getByText('Searched files')).toBeTruthy(); + }); + + test('collapsed view calls openFile when clicked with filePath', () => { + const filePath = '/path/to/file.ts'; + const msg: ToolReturnParseResult = { + content: 'Opened file', + type: 'open', + filePath, + }; + + const { getByText } = render( + , + ); + + fireEvent.click(getByText('Opened file')); + expect(mockOpenFile).toHaveBeenCalledWith(filePath); + }); + + test('renders expanded view by default (collapsed=false)', () => { + const msg: ToolReturnParseResult = { + content: 'Replaced code', + title: 'myFile.ts', + type: 'modify', + filePath: '/path/to/myFile.ts', + }; + + const { container } = render( + , + ); + + expect(container.querySelector('.tool-return-collapsed')).toBeNull(); + }); }); diff --git a/src/rovo-dev/ui/tools/ToolReturnItem.tsx b/src/rovo-dev/ui/tools/ToolReturnItem.tsx index 8d509f389..2cf6e1305 100644 --- a/src/rovo-dev/ui/tools/ToolReturnItem.tsx +++ b/src/rovo-dev/ui/tools/ToolReturnItem.tsx @@ -13,7 +13,8 @@ export const ToolReturnParsedItem: React.FC<{ msg: ToolReturnParseResult; openFile: OpenFileFunc; onLinkClick: (href: string) => void; -}> = ({ msg, openFile, onLinkClick }) => { + collapsed?: boolean; +}> = ({ msg, openFile, onLinkClick, collapsed = false }) => { const toolIcon = React.useMemo(() => (msg.type ? iconMap[msg.type] : undefined), [msg.type]); const filePathClass = msg.filePath && msg.type !== 'delete' ? 'tool-return-file-path' : ''; @@ -28,6 +29,21 @@ export const ToolReturnParsedItem: React.FC<{ [msg.filePath, msg.type, openFile], ); + if (collapsed) { + return ( + + {toolIcon} + + {msg.content ?? ''} + {msg.title ? ` — ${msg.title}` : ''} + + + ); + } + return ( {toolIcon}