@@ -2,15 +2,14 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from "
22import { useSize } from "react-use"
33import { useTranslation , Trans } from "react-i18next"
44import deepEqual from "fast-deep-equal"
5- import { VSCodeBadge , VSCodeButton } from "@vscode/webview-ui-toolkit/react"
5+ import { VSCodeBadge } from "@vscode/webview-ui-toolkit/react"
66
77import type { ClineMessage , FollowUpData , SuggestionItem } from "@roo-code/types"
88
99import { ClineApiReqInfo , ClineAskUseMcpServer , ClineSayTool } from "@roo/ExtensionMessage"
1010import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences"
1111import { safeJsonParse } from "@roo/safeJsonParse"
1212
13- import { useCopyToClipboard } from "@src/utils/clipboard"
1413import { useExtensionState } from "@src/context/ExtensionStateContext"
1514import { findMatchingResourceOrTemplate } from "@src/utils/mcp"
1615import { vscode } from "@src/utils/vscode"
@@ -21,7 +20,6 @@ import { Button } from "@src/components/ui"
2120import { ToolUseBlock , ToolUseBlockHeader } from "../common/ToolUseBlock"
2221import UpdateTodoListToolBlock from "./UpdateTodoListToolBlock"
2322import CodeAccordian from "../common/CodeAccordian"
24- import CodeBlock from "../common/CodeBlock"
2523import MarkdownBlock from "../common/MarkdownBlock"
2624import { ReasoningBlock } from "./ReasoningBlock"
2725import Thumbnails from "../common/Thumbnails"
@@ -42,6 +40,7 @@ import { AutoApprovedRequestLimitWarning } from "./AutoApprovedRequestLimitWarni
4240import { CondenseContextErrorRow , CondensingContextRow , ContextCondenseRow } from "./ContextCondenseRow"
4341import CodebaseSearchResultsDisplay from "./CodebaseSearchResultsDisplay"
4442import { McpExecution } from "./McpExecution"
43+ import { CollapsibleErrorSection } from "./CollapsibleErrorSection"
4544
4645interface ChatRowProps {
4746 message : ClineMessage
@@ -115,10 +114,7 @@ export const ChatRowContent = ({
115114
116115 const [ reasoningCollapsed , setReasoningCollapsed ] = useState ( true )
117116 const [ isDiffErrorExpanded , setIsDiffErrorExpanded ] = useState ( false )
118- const [ showCopySuccess , setShowCopySuccess ] = useState ( false )
119117 const [ isErrorExpanded , setIsErrorExpanded ] = useState ( false ) // Default collapsed like diff_error
120- const [ showErrorCopySuccess , setShowErrorCopySuccess ] = useState ( false )
121- const { copyWithFeedback } = useCopyToClipboard ( )
122118
123119 // Memoized callback to prevent re-renders caused by inline arrow functions.
124120 const handleToggleExpand = useCallback ( ( ) => {
@@ -904,63 +900,13 @@ export const ChatRowContent = ({
904900 switch ( message . say ) {
905901 case "diff_error" :
906902 return (
907- < div >
908- < div className = "mt-0 overflow-hidden mb-2" >
909- < div
910- className = { `${
911- isDiffErrorExpanded ? "border-b border-vscode-editorGroup-border" : ""
912- } font-normal text-base text-vscode-editor-foreground flex items-center justify-between cursor-pointer focus:outline focus:outline-2 focus:outline-vscode-focusBorder`}
913- role = "button"
914- tabIndex = { 0 }
915- aria-expanded = { isDiffErrorExpanded }
916- aria-label = { t ( "chat:diffError.title" ) }
917- onClick = { ( ) => setIsDiffErrorExpanded ( ! isDiffErrorExpanded ) }
918- onKeyDown = { ( e ) => {
919- if ( e . key === "Enter" || e . key === " " ) {
920- e . preventDefault ( )
921- setIsDiffErrorExpanded ( ! isDiffErrorExpanded )
922- }
923- } } >
924- < div className = "flex items-center gap-2.5 flex-grow" >
925- < span
926- className = "codicon codicon-warning text-vscode-editorWarning-foreground opacity-80"
927- style = { { fontSize : 16 , marginBottom : "-1.5px" } } > </ span >
928- < span className = "font-bold" > { t ( "chat:diffError.title" ) } </ span >
929- </ div >
930- < div className = "flex items-center" >
931- < VSCodeButton
932- appearance = "icon"
933- className = "p-[3px] h-6 mr-1 text-vscode-editor-foreground flex items-center justify-center bg-transparent"
934- onClick = { ( e ) => {
935- e . stopPropagation ( )
936-
937- // Call copyWithFeedback and handle the Promise
938- copyWithFeedback ( message . text || "" ) . then ( ( success ) => {
939- if ( success ) {
940- // Show checkmark
941- setShowCopySuccess ( true )
942-
943- // Reset after a brief delay
944- setTimeout ( ( ) => {
945- setShowCopySuccess ( false )
946- } , 1000 )
947- }
948- } )
949- } } >
950- < span
951- className = { `codicon codicon-${ showCopySuccess ? "check" : "copy" } ` } > </ span >
952- </ VSCodeButton >
953- < span
954- className = { `codicon codicon-chevron-${ isDiffErrorExpanded ? "up" : "down" } ` } > </ span >
955- </ div >
956- </ div >
957- { isDiffErrorExpanded && (
958- < div className = "p-2 bg-vscode-editor-background" >
959- < CodeBlock source = { message . text || "" } language = "xml" />
960- </ div >
961- ) }
962- </ div >
963- </ div >
903+ < CollapsibleErrorSection
904+ title = { t ( "chat:diffError.title" ) }
905+ content = { message . text }
906+ language = "xml"
907+ isExpanded = { isDiffErrorExpanded }
908+ onToggleExpand = { ( ) => setIsDiffErrorExpanded ( ! isDiffErrorExpanded ) }
909+ />
964910 )
965911 case "subtask_result" :
966912 return (
@@ -1127,59 +1073,16 @@ export const ChatRowContent = ({
11271073 </ div >
11281074 )
11291075 case "error" :
1076+ // Detect language based on content - check if it contains XML-like error tags
1077+ const errorLanguage = message . text ?. includes ( "<error>" ) ? "xml" : "text"
11301078 return (
1131- < div >
1132- < div className = "mt-0 overflow-hidden mb-2" >
1133- < div
1134- className = { `${
1135- isErrorExpanded ? "border-b border-vscode-editorGroup-border" : ""
1136- } font-normal text-base text-vscode-editor-foreground flex items-center justify-between cursor-pointer focus:outline focus:outline-2 focus:outline-vscode-focusBorder`}
1137- role = "button"
1138- tabIndex = { 0 }
1139- aria-expanded = { isErrorExpanded }
1140- aria-label = { message . title || t ( "chat:error" ) }
1141- onClick = { ( ) => setIsErrorExpanded ( ! isErrorExpanded ) }
1142- onKeyDown = { ( e ) => {
1143- if ( e . key === "Enter" || e . key === " " ) {
1144- e . preventDefault ( )
1145- setIsErrorExpanded ( ! isErrorExpanded )
1146- }
1147- } } >
1148- < div className = "flex items-center gap-2.5 flex-grow" >
1149- < span
1150- className = "codicon codicon-warning text-vscode-editorWarning-foreground opacity-80"
1151- style = { { fontSize : 16 , marginBottom : "-1.5px" } } > </ span >
1152- < span className = "font-bold" > { message . title || t ( "chat:error" ) } </ span >
1153- </ div >
1154- < div className = "flex items-center" >
1155- < VSCodeButton
1156- appearance = "icon"
1157- className = "p-[3px] h-6 mr-1 text-vscode-editor-foreground flex items-center justify-center bg-transparent"
1158- onClick = { ( e ) => {
1159- e . stopPropagation ( )
1160- copyWithFeedback ( message . text || "" ) . then ( ( success ) => {
1161- if ( success ) {
1162- setShowErrorCopySuccess ( true )
1163- setTimeout ( ( ) => {
1164- setShowErrorCopySuccess ( false )
1165- } , 1000 )
1166- }
1167- } )
1168- } } >
1169- < span
1170- className = { `codicon codicon-${ showErrorCopySuccess ? "check" : "copy" } ` } > </ span >
1171- </ VSCodeButton >
1172- < span
1173- className = { `codicon codicon-chevron-${ isErrorExpanded ? "up" : "down" } ` } > </ span >
1174- </ div >
1175- </ div >
1176- { isErrorExpanded && (
1177- < div className = "p-2 bg-vscode-editor-background" >
1178- < CodeBlock source = { message . text || "" } language = "xml" />
1179- </ div >
1180- ) }
1181- </ div >
1182- </ div >
1079+ < CollapsibleErrorSection
1080+ title = { message . title || t ( "chat:error" ) }
1081+ content = { message . text }
1082+ language = { errorLanguage }
1083+ isExpanded = { isErrorExpanded }
1084+ onToggleExpand = { ( ) => setIsErrorExpanded ( ! isErrorExpanded ) }
1085+ />
11831086 )
11841087 case "completion_result" :
11851088 return (
0 commit comments