mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
refactor: address code review feedback for error display
- Extract shared CollapsibleErrorSection component to eliminate code duplication - Use Tailwind CSS classes instead of inline styles for consistency - Add proper accessibility attributes (role, tabIndex, aria-expanded, keyboard handlers) - Auto-detect language for error content (xml for error tags, text otherwise) - Maintain feature parity between error and diff_error displays
This commit is contained in:
parent
446bafb812
commit
44e4feecb8
2 changed files with 91 additions and 115 deletions
|
|
@ -2,7 +2,7 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from "
|
|||
import { useSize } from "react-use"
|
||||
import { useTranslation, Trans } from "react-i18next"
|
||||
import deepEqual from "fast-deep-equal"
|
||||
import { VSCodeBadge, VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||
import { VSCodeBadge } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ClineMessage, FollowUpData, SuggestionItem } from "@roo-code/types"
|
||||
import { Mode } from "@roo/modes"
|
||||
|
|
@ -11,7 +11,6 @@ import { ClineApiReqInfo, ClineAskUseMcpServer, ClineSayTool } from "@roo/Extens
|
|||
import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences"
|
||||
import { safeJsonParse } from "@roo/safeJsonParse"
|
||||
|
||||
import { useCopyToClipboard } from "@src/utils/clipboard"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
import { findMatchingResourceOrTemplate } from "@src/utils/mcp"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
|
@ -22,7 +21,6 @@ import { Button } from "@src/components/ui"
|
|||
import { ToolUseBlock, ToolUseBlockHeader } from "../common/ToolUseBlock"
|
||||
import UpdateTodoListToolBlock from "./UpdateTodoListToolBlock"
|
||||
import CodeAccordian from "../common/CodeAccordian"
|
||||
import CodeBlock from "../common/CodeBlock"
|
||||
import MarkdownBlock from "../common/MarkdownBlock"
|
||||
import { ReasoningBlock } from "./ReasoningBlock"
|
||||
import Thumbnails from "../common/Thumbnails"
|
||||
|
|
@ -47,6 +45,7 @@ import { McpExecution } from "./McpExecution"
|
|||
import { ChatTextArea } from "./ChatTextArea"
|
||||
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
|
||||
import { useSelectedModel } from "../ui/hooks/useSelectedModel"
|
||||
import { CollapsibleErrorSection } from "./CollapsibleErrorSection"
|
||||
|
||||
interface ChatRowProps {
|
||||
message: ClineMessage
|
||||
|
|
@ -120,14 +119,11 @@ export const ChatRowContent = ({
|
|||
const { info: model } = useSelectedModel(apiConfiguration)
|
||||
const [reasoningCollapsed, setReasoningCollapsed] = useState(true)
|
||||
const [isDiffErrorExpanded, setIsDiffErrorExpanded] = useState(false)
|
||||
const [showCopySuccess, setShowCopySuccess] = useState(false)
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
const [editedContent, setEditedContent] = useState("")
|
||||
const [editMode, setEditMode] = useState<Mode>(mode || "code")
|
||||
const [editImages, setEditImages] = useState<string[]>([])
|
||||
const [isErrorExpanded, setIsErrorExpanded] = useState(false) // Default collapsed like diff_error
|
||||
const [showErrorCopySuccess, setShowErrorCopySuccess] = useState(false)
|
||||
const { copyWithFeedback } = useCopyToClipboard()
|
||||
|
||||
// Handle message events for image selection during edit mode
|
||||
useEffect(() => {
|
||||
|
|
@ -961,63 +957,13 @@ export const ChatRowContent = ({
|
|||
switch (message.say) {
|
||||
case "diff_error":
|
||||
return (
|
||||
<div>
|
||||
<div className="mt-0 overflow-hidden mb-2">
|
||||
<div
|
||||
className={`${
|
||||
isDiffErrorExpanded ? "border-b border-vscode-editorGroup-border" : ""
|
||||
} font-normal text-base text-vscode-editor-foreground flex items-center justify-between cursor-pointer focus:outline focus:outline-2 focus:outline-vscode-focusBorder`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-expanded={isDiffErrorExpanded}
|
||||
aria-label={t("chat:diffError.title")}
|
||||
onClick={() => setIsDiffErrorExpanded(!isDiffErrorExpanded)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
setIsDiffErrorExpanded(!isDiffErrorExpanded)
|
||||
}
|
||||
}}>
|
||||
<div className="flex items-center gap-2.5 flex-grow">
|
||||
<span
|
||||
className="codicon codicon-warning text-vscode-editorWarning-foreground opacity-80"
|
||||
style={{ fontSize: 16, marginBottom: "-1.5px" }}></span>
|
||||
<span className="font-bold">{t("chat:diffError.title")}</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<VSCodeButton
|
||||
appearance="icon"
|
||||
className="p-[3px] h-6 mr-1 text-vscode-editor-foreground flex items-center justify-center bg-transparent"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
|
||||
// Call copyWithFeedback and handle the Promise
|
||||
copyWithFeedback(message.text || "").then((success) => {
|
||||
if (success) {
|
||||
// Show checkmark
|
||||
setShowCopySuccess(true)
|
||||
|
||||
// Reset after a brief delay
|
||||
setTimeout(() => {
|
||||
setShowCopySuccess(false)
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
}}>
|
||||
<span
|
||||
className={`codicon codicon-${showCopySuccess ? "check" : "copy"}`}></span>
|
||||
</VSCodeButton>
|
||||
<span
|
||||
className={`codicon codicon-chevron-${isDiffErrorExpanded ? "up" : "down"}`}></span>
|
||||
</div>
|
||||
</div>
|
||||
{isDiffErrorExpanded && (
|
||||
<div className="p-2 bg-vscode-editor-background">
|
||||
<CodeBlock source={message.text || ""} language="xml" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<CollapsibleErrorSection
|
||||
title={t("chat:diffError.title")}
|
||||
content={message.text}
|
||||
language="xml"
|
||||
isExpanded={isDiffErrorExpanded}
|
||||
onToggleExpand={() => setIsDiffErrorExpanded(!isDiffErrorExpanded)}
|
||||
/>
|
||||
)
|
||||
case "subtask_result":
|
||||
return (
|
||||
|
|
@ -1216,59 +1162,16 @@ export const ChatRowContent = ({
|
|||
</div>
|
||||
)
|
||||
case "error":
|
||||
// Detect language based on content - check if it contains XML-like error tags
|
||||
const errorLanguage = message.text?.includes("<error>") ? "xml" : "text"
|
||||
return (
|
||||
<div>
|
||||
<div className="mt-0 overflow-hidden mb-2">
|
||||
<div
|
||||
className={`${
|
||||
isErrorExpanded ? "border-b border-vscode-editorGroup-border" : ""
|
||||
} font-normal text-base text-vscode-editor-foreground flex items-center justify-between cursor-pointer focus:outline focus:outline-2 focus:outline-vscode-focusBorder`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-expanded={isErrorExpanded}
|
||||
aria-label={message.title || t("chat:error")}
|
||||
onClick={() => setIsErrorExpanded(!isErrorExpanded)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
setIsErrorExpanded(!isErrorExpanded)
|
||||
}
|
||||
}}>
|
||||
<div className="flex items-center gap-2.5 flex-grow">
|
||||
<span
|
||||
className="codicon codicon-warning text-vscode-editorWarning-foreground opacity-80"
|
||||
style={{ fontSize: 16, marginBottom: "-1.5px" }}></span>
|
||||
<span className="font-bold">{message.title || t("chat:error")}</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<VSCodeButton
|
||||
appearance="icon"
|
||||
className="p-[3px] h-6 mr-1 text-vscode-editor-foreground flex items-center justify-center bg-transparent"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
copyWithFeedback(message.text || "").then((success) => {
|
||||
if (success) {
|
||||
setShowErrorCopySuccess(true)
|
||||
setTimeout(() => {
|
||||
setShowErrorCopySuccess(false)
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
}}>
|
||||
<span
|
||||
className={`codicon codicon-${showErrorCopySuccess ? "check" : "copy"}`}></span>
|
||||
</VSCodeButton>
|
||||
<span
|
||||
className={`codicon codicon-chevron-${isErrorExpanded ? "up" : "down"}`}></span>
|
||||
</div>
|
||||
</div>
|
||||
{isErrorExpanded && (
|
||||
<div className="p-2 bg-vscode-editor-background">
|
||||
<CodeBlock source={message.text || ""} language="xml" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<CollapsibleErrorSection
|
||||
title={message.title || t("chat:error")}
|
||||
content={message.text}
|
||||
language={errorLanguage}
|
||||
isExpanded={isErrorExpanded}
|
||||
onToggleExpand={() => setIsErrorExpanded(!isErrorExpanded)}
|
||||
/>
|
||||
)
|
||||
case "completion_result":
|
||||
return (
|
||||
|
|
|
|||
73
webview-ui/src/components/chat/CollapsibleErrorSection.tsx
Normal file
73
webview-ui/src/components/chat/CollapsibleErrorSection.tsx
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import React from "react"
|
||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||
import CodeBlock from "../common/CodeBlock"
|
||||
import { useCopyToClipboard } from "@src/utils/clipboard"
|
||||
|
||||
interface CollapsibleErrorSectionProps {
|
||||
title: string
|
||||
content: string | null | undefined
|
||||
language?: string
|
||||
isExpanded: boolean
|
||||
onToggleExpand: () => void
|
||||
}
|
||||
|
||||
export const CollapsibleErrorSection: React.FC<CollapsibleErrorSectionProps> = ({
|
||||
title,
|
||||
content,
|
||||
language = "xml",
|
||||
isExpanded,
|
||||
onToggleExpand,
|
||||
}) => {
|
||||
const [showCopySuccess, setShowCopySuccess] = React.useState(false)
|
||||
const { copyWithFeedback } = useCopyToClipboard()
|
||||
|
||||
const handleCopy = async (e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
const success = await copyWithFeedback(content || "")
|
||||
if (success) {
|
||||
setShowCopySuccess(true)
|
||||
setTimeout(() => setShowCopySuccess(false), 1000)
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
onToggleExpand()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-0 overflow-hidden mb-2">
|
||||
<div
|
||||
className={`${
|
||||
isExpanded ? "border-b border-vscode-editorGroup-border" : ""
|
||||
} font-normal text-base text-vscode-editor-foreground flex items-center justify-between cursor-pointer focus:outline focus:outline-2 focus:outline-vscode-focusBorder`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-expanded={isExpanded}
|
||||
aria-label={title}
|
||||
onClick={onToggleExpand}
|
||||
onKeyDown={handleKeyDown}>
|
||||
<div className="flex items-center gap-2.5 flex-grow">
|
||||
<span className="codicon codicon-warning text-vscode-editorWarning-foreground opacity-80 text-base -mb-0.5"></span>
|
||||
<span className="font-bold">{title}</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<VSCodeButton
|
||||
appearance="icon"
|
||||
className="p-[3px] h-6 mr-1 text-vscode-editor-foreground flex items-center justify-center bg-transparent"
|
||||
onClick={handleCopy}>
|
||||
<span className={`codicon codicon-${showCopySuccess ? "check" : "copy"}`}></span>
|
||||
</VSCodeButton>
|
||||
<span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded && (
|
||||
<div className="p-2 bg-vscode-editor-background">
|
||||
<CodeBlock source={content || ""} language={language} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue