feat: add error boundaries for graceful error handling (Phase 3.4)
Implement React Error Boundaries to catch and handle errors gracefully without crashing the entire UI. Provides helpful recovery mechanisms. Changes: - Create ErrorBoundary component module - BaseErrorBoundary abstract class (shared logic) - CryptoErrorBoundary (crypto operation errors) - ApiErrorBoundary (API communication errors) - GenericErrorBoundary (general component errors) - Error boundary features - Catches rendering and lifecycle errors - Logs errors to console for debugging - Displays helpful, contextual error messages - Provides retry/reload buttons for recovery - Optional custom fallback UI via props - Optional onReset callback for custom recovery - Integrate error boundaries into routes - Wrap SealedSecretList with ApiErrorBoundary - Wrap SealedSecretDetail with ApiErrorBoundary - Wrap SealingKeysView with ApiErrorBoundary - Wrap SettingsPage with GenericErrorBoundary - Wrap SecretDetailsSection with GenericErrorBoundary Error types and messages: - Crypto errors: Certificate, browser compatibility, malformed data - API errors: Cluster connection, controller config, network - Generic errors: Unexpected errors with simple recovery message Benefits: - App doesn't crash completely on errors - Users can continue using unaffected features - Clear, actionable troubleshooting steps - Professional error presentation - Production-ready error handling - Easier debugging with console logs Build: 354.92 kB (97.76 kB gzipped), +2.47 kB (+0.7%) Phase 3.4 complete. 10 of 14 phases done (71%). Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
registerSidebarEntry,
|
||||
} from '@kinvolk/headlamp-plugin/lib';
|
||||
import React from 'react';
|
||||
import { ApiErrorBoundary, GenericErrorBoundary } from './components/ErrorBoundary';
|
||||
import { SealedSecretDetail } from './components/SealedSecretDetail';
|
||||
import { SealedSecretList } from './components/SealedSecretList';
|
||||
import { SealingKeysView } from './components/SealingKeysView';
|
||||
@@ -71,7 +72,11 @@ registerSidebarEntry({
|
||||
registerRoute({
|
||||
path: '/sealedsecrets',
|
||||
sidebar: 'sealed-secrets-list',
|
||||
component: () => <SealedSecretList />,
|
||||
component: () => (
|
||||
<ApiErrorBoundary>
|
||||
<SealedSecretList />
|
||||
</ApiErrorBoundary>
|
||||
),
|
||||
exact: true,
|
||||
});
|
||||
|
||||
@@ -79,7 +84,11 @@ registerRoute({
|
||||
registerRoute({
|
||||
path: '/sealedsecrets/:namespace/:name',
|
||||
sidebar: 'sealed-secrets-list',
|
||||
component: () => <SealedSecretDetail />,
|
||||
component: () => (
|
||||
<ApiErrorBoundary>
|
||||
<SealedSecretDetail />
|
||||
</ApiErrorBoundary>
|
||||
),
|
||||
exact: true,
|
||||
name: 'sealedsecret',
|
||||
});
|
||||
@@ -88,7 +97,11 @@ registerRoute({
|
||||
registerRoute({
|
||||
path: '/sealedsecrets/keys',
|
||||
sidebar: 'sealing-keys',
|
||||
component: () => <SealingKeysView />,
|
||||
component: () => (
|
||||
<ApiErrorBoundary>
|
||||
<SealingKeysView />
|
||||
</ApiErrorBoundary>
|
||||
),
|
||||
exact: true,
|
||||
});
|
||||
|
||||
@@ -96,7 +109,11 @@ registerRoute({
|
||||
registerRoute({
|
||||
path: '/sealedsecrets/settings',
|
||||
sidebar: 'sealed-secrets-settings',
|
||||
component: () => <SettingsPage />,
|
||||
component: () => (
|
||||
<GenericErrorBoundary>
|
||||
<SettingsPage />
|
||||
</GenericErrorBoundary>
|
||||
),
|
||||
exact: true,
|
||||
});
|
||||
|
||||
@@ -107,7 +124,11 @@ registerRoute({
|
||||
*/
|
||||
registerDetailsViewSection(({ resource }) => {
|
||||
if (resource?.kind === 'Secret') {
|
||||
return <SecretDetailsSection resource={resource} />;
|
||||
return (
|
||||
<GenericErrorBoundary>
|
||||
<SecretDetailsSection resource={resource} />
|
||||
</GenericErrorBoundary>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user