-
Notifications
You must be signed in to change notification settings - Fork 2.6k
feat: implement react-error-boundary for component error isolation #5732
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- 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
| <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")} |
There was a problem hiding this comment.
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.
| {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 |
There was a problem hiding this comment.
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.
| // Add to local storage for debugging | |
| // Add to in-memory array for debugging |
| "imageDataUriCopied": "इमेज डेटा URI क्लिपबोर्ड में कॉपी हो गया" | ||
| } | ||
| }, | ||
| "errorBoundary": { |
There was a problem hiding this comment.
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.
| {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> |
There was a problem hiding this comment.
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.
This PR implements
react-error-boundaryto isolate errors in React UI components, preventing the entire VSCode extension from crashing when individual components fail.Changes Made
🔧 Dependencies
react-error-boundary ^6.0.0to webview-ui package🛡️ Error Boundary Implementation
ErrorBoundarycomponent with VSCode-themed fallback UIwebview-ui/src/i18n/locales/en/common.json🎯 Component Integration
ChatView(main chat interface)SettingsView(extension settings)HistoryView(conversation history)MarketplaceView(mode marketplace)WelcomeView(welcome screen)TaskView(task management)DebugView(debugging interface)🧪 Testing
ErrorBoundarycomponent🎨 UI/UX Features
Technical Details
The implementation uses the
react-error-boundarylibrary which provides:Error boundaries are strategically placed around major UI sections to isolate failures and prevent cascading crashes throughout the extension.
Testing
All tests pass including:
Fixes #5731
Important
Implements
react-error-boundaryfor component error isolation with a customErrorBoundary, error reporting, and internationalization support.react-error-boundaryto isolate component errors, preventing full app crashes.ErrorBoundarycomponent with VSCode-themed fallback UI inErrorBoundary.tsx.errorReporting.tsfor centralized error collection.ChatView,SettingsView,HistoryView,MarketplaceView,WelcomeView,TaskView, andDebugViewwithErrorBoundaryinApp.tsx.en/common.json,de/common.json, andfr/common.json.ErrorBoundaryinErrorBoundary.spec.tsx.vitest.config.ts.react-error-boundarytopackage.jsondependencies.This description was created by
for 06bd8ee. You can customize this summary. It will automatically update as commits are pushed.