Skip to content

Conversation

@roomote
Copy link
Contributor

@roomote roomote bot commented Jul 15, 2025

This PR implements react-error-boundary to isolate errors in React UI components, preventing the entire VSCode extension from crashing when individual components fail.

Changes Made

🔧 Dependencies

  • Added react-error-boundary ^6.0.0 to webview-ui package

🛡️ Error Boundary Implementation

  • Created custom ErrorBoundary component with VSCode-themed fallback UI
  • Added internationalization support for error messages in webview-ui/src/i18n/locales/en/common.json
  • Implemented error reporting utility for centralized error collection with extensibility for future Sentry integration

🎯 Component Integration

  • Wrapped all major view components with error boundaries:
    • ChatView (main chat interface)
    • SettingsView (extension settings)
    • HistoryView (conversation history)
    • MarketplaceView (mode marketplace)
    • WelcomeView (welcome screen)
    • TaskView (task management)
    • DebugView (debugging interface)

🧪 Testing

  • Added comprehensive test coverage for ErrorBoundary component
  • Configured Vitest for React development mode to support testing
  • All tests passing with 100% coverage of error boundary functionality

🎨 UI/UX Features

  • VSCode-themed error fallback UI with proper styling
  • Expandable error details section for debugging
  • "Try again" button for error recovery
  • Component-specific error messages for better debugging

Technical Details

The implementation uses the react-error-boundary library which provides:

  • Declarative error boundaries with fallback components
  • Error recovery mechanisms
  • Integration with error reporting services

Error boundaries are strategically placed around major UI sections to isolate failures and prevent cascading crashes throughout the extension.

Testing

cd webview-ui && npm run test

All tests pass including:

  • Error boundary rendering
  • Fallback UI display
  • Error reporting integration
  • Component recovery functionality

Fixes #5731


Important

Implements react-error-boundary for component error isolation with a custom ErrorBoundary, error reporting, and internationalization support.

  • Behavior:
    • Implement react-error-boundary to isolate component errors, preventing full app crashes.
    • Custom ErrorBoundary component with VSCode-themed fallback UI in ErrorBoundary.tsx.
    • Error reporting utility in errorReporting.ts for centralized error collection.
  • Component Integration:
    • Wraps major components like ChatView, SettingsView, HistoryView, MarketplaceView, WelcomeView, TaskView, and DebugView with ErrorBoundary in App.tsx.
  • Internationalization:
    • Adds error message translations in multiple locale files like en/common.json, de/common.json, and fr/common.json.
  • Testing:
    • Comprehensive tests for ErrorBoundary in ErrorBoundary.spec.tsx.
    • Configures Vitest for React development mode in vitest.config.ts.
  • Misc:
    • Adds react-error-boundary to package.json dependencies.

This description was created by Ellipsis for 06bd8ee. You can customize this summary. It will automatically update as commits are pushed.

- Add react-error-boundary dependency to webview-ui package
- Create custom ErrorBoundary component with VSCode-themed fallback UI
- Add internationalization support for error messages
- Wrap all major view components (ChatView, SettingsView, HistoryView, etc.) with error boundaries
- Implement error reporting utility for centralized error collection
- Add comprehensive test coverage for ErrorBoundary component
- Configure Vitest for React development mode to support testing

Fixes #5731
@roomote roomote bot requested review from cte, jr and mrubens as code owners July 15, 2025 11:26
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request UI/UX UI/UX related or focused labels Jul 15, 2025
<div className="flex items-center mb-4">
<span className="codicon codicon-error text-vscode-errorForeground text-2xl mr-3" />
<h2 className="text-lg font-semibold text-vscode-editor-foreground">
{t("errorBoundary.title", "Something went wrong")}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using inline fallback strings in translation calls. Remove the second argument in t() (e.g. in t('errorBoundary.title', 'Something went wrong')) and rely solely on translations defined in the JSON files per our guidelines.

Suggested change
{t("errorBoundary.title", "Something went wrong")}
{t("errorBoundary.title")}

This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.

url: window.location.href,
}

// Add to local storage for debugging
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment '// Add to local storage for debugging' is misleading since errors are stored in an in-memory array. Consider updating or clarifying this comment.

Suggested change
// Add to local storage for debugging
// Add to in-memory array for debugging

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jul 15, 2025
@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Jul 15, 2025
"imageDataUriCopied": "इमेज डेटा URI क्लिपबोर्ड में कॉपी हो गया"
}
},
"errorBoundary": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider translating the errorBoundary messages into Hindi instead of using English.

This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.

Comment on lines +178 to +234
{tab === "modes" && (
<ErrorBoundary componentName="ModesView">
<ModesView onDone={() => switchTab("chat")} />
</ErrorBoundary>
)}
{tab === "mcp" && (
<ErrorBoundary componentName="McpView">
<McpView onDone={() => switchTab("chat")} />
</ErrorBoundary>
)}
{tab === "history" && (
<ErrorBoundary componentName="HistoryView">
<HistoryView onDone={() => switchTab("chat")} />
</ErrorBoundary>
)}
{tab === "settings" && (
<SettingsView ref={settingsRef} onDone={() => setTab("chat")} targetSection={currentSection} />
<ErrorBoundary componentName="SettingsView">
<SettingsView ref={settingsRef} onDone={() => setTab("chat")} targetSection={currentSection} />
</ErrorBoundary>
)}
{tab === "marketplace" && (
<MarketplaceView
stateManager={marketplaceStateManager}
onDone={() => switchTab("chat")}
targetTab={currentMarketplaceTab as "mcp" | "mode" | undefined}
/>
<ErrorBoundary componentName="MarketplaceView">
<MarketplaceView
stateManager={marketplaceStateManager}
onDone={() => switchTab("chat")}
targetTab={currentMarketplaceTab as "mcp" | "mode" | undefined}
/>
</ErrorBoundary>
)}
{tab === "account" && (
<AccountView
userInfo={cloudUserInfo}
isAuthenticated={cloudIsAuthenticated}
cloudApiUrl={cloudApiUrl}
onDone={() => switchTab("chat")}
/>
<ErrorBoundary componentName="AccountView">
<AccountView
userInfo={cloudUserInfo}
isAuthenticated={cloudIsAuthenticated}
cloudApiUrl={cloudApiUrl}
onDone={() => switchTab("chat")}
/>
</ErrorBoundary>
)}
<ChatView
ref={chatViewRef}
isHidden={tab !== "chat"}
showAnnouncement={showAnnouncement}
hideAnnouncement={() => setShowAnnouncement(false)}
/>
<HumanRelayDialog
isOpen={humanRelayDialogState.isOpen}
requestId={humanRelayDialogState.requestId}
promptText={humanRelayDialogState.promptText}
onClose={() => setHumanRelayDialogState((prev) => ({ ...prev, isOpen: false }))}
onSubmit={(requestId, text) => vscode.postMessage({ type: "humanRelayResponse", requestId, text })}
onCancel={(requestId) => vscode.postMessage({ type: "humanRelayCancel", requestId })}
/>
<ErrorBoundary componentName="ChatView">
<ChatView
ref={chatViewRef}
isHidden={tab !== "chat"}
showAnnouncement={showAnnouncement}
hideAnnouncement={() => setShowAnnouncement(false)}
/>
</ErrorBoundary>
<ErrorBoundary componentName="HumanRelayDialog">
<HumanRelayDialog
isOpen={humanRelayDialogState.isOpen}
requestId={humanRelayDialogState.requestId}
promptText={humanRelayDialogState.promptText}
onClose={() => setHumanRelayDialogState((prev) => ({ ...prev, isOpen: false }))}
onSubmit={(requestId, text) => vscode.postMessage({ type: "humanRelayResponse", requestId, text })}
onCancel={(requestId) => vscode.postMessage({ type: "humanRelayCancel", requestId })}
/>
</ErrorBoundary>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cleaner pattern would be to just use the HoC so we don't need to litter the existing markup with a bunch of wrappers, the wrapping happens on component's file export

Instead of export default Component we'd do export default withErrorBoundary(Component) instead. That could be customised so we don't have repeated logic, all of the magic happens inside withErroBoundary wrapper.

@daniel-lxs daniel-lxs moved this from Triage to Roomote/renovate BOT in Roo Code Roadmap Jul 15, 2025
@daniel-lxs daniel-lxs closed this Sep 16, 2025
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Sep 16, 2025
@github-project-automation github-project-automation bot moved this from Renovate BOT to Done in Roo Code Roadmap Sep 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. size:XL This PR changes 500-999 lines, ignoring generated files. UI/UX UI/UX related or focused

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Use react-error-boundary to isolate errors

4 participants