Frontend: globale Error Boundary (Review F4) + dist-Rebuild

JS-Fehler in einer View fuehrten zum weissen Screen ohne Meldung; jetzt Fehleranzeige
mit Neu-laden-Knopf am App-Root (GraphView behaelt seine eigene Boundary).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-02 11:08:25 +02:00
parent 68ad291a8f
commit 60765469aa
7 changed files with 109 additions and 68 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -7,8 +7,8 @@
<link rel="manifest" href="/manifest.webmanifest" /> <link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title> <title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-KW1c6Ww8.js"></script> <script type="module" crossorigin src="/assets/index-CrYzXlx6.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BljJ8MOS.css"> <link rel="stylesheet" crossorigin href="/assets/index-_Rap01H_.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
@@ -0,0 +1,38 @@
import React from "react"
// Globale Error Boundary (Review F4): Ein JS-Fehler in einer View riss vorher die komplette
// App in einen weißen Screen. Hier: Fehler anzeigen + Neu-laden-Knopf, Rest bleibt bedienbar
// nach Reload. (GraphView hat zusätzlich seine eigene Boundary für Three.js-Crashes.)
interface State { error: Error | null }
export class AppErrorBoundary extends React.Component<React.PropsWithChildren, State> {
state: State = { error: null }
static getDerivedStateFromError(error: Error): State {
return { error }
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error("Unbehandelter UI-Fehler:", error, info.componentStack)
}
render() {
if (!this.state.error) return this.props.children
return (
<div className="min-h-screen flex items-center justify-center bg-neutral-950 text-neutral-200 p-8">
<div className="max-w-lg space-y-4 text-center">
<div className="text-2xl">Da ist etwas schiefgelaufen.</div>
<div className="text-sm text-neutral-400 break-all">
{this.state.error.message}
</div>
<button
className="px-4 py-2 rounded-lg bg-neutral-800 hover:bg-neutral-700 border border-neutral-700"
onClick={() => window.location.reload()}
>
Neu laden
</button>
</div>
</div>
)
}
}
+6 -3
View File
@@ -2,6 +2,7 @@ import React from "react"
import ReactDOM from "react-dom/client" import ReactDOM from "react-dom/client"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import App from "./App" import App from "./App"
import { AppErrorBoundary } from "./components/AppErrorBoundary"
import "./index.css" import "./index.css"
// Zentraler Daten-Layer: Caching, Dedup, Retry, Polling pro Query-Hook. // Zentraler Daten-Layer: Caching, Dedup, Retry, Polling pro Query-Hook.
@@ -17,8 +18,10 @@ const queryClient = new QueryClient({
ReactDOM.createRoot(document.getElementById("root")!).render( ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode> <React.StrictMode>
<QueryClientProvider client={queryClient}> <AppErrorBoundary>
<App /> <QueryClientProvider client={queryClient}>
</QueryClientProvider> <App />
</QueryClientProvider>
</AppErrorBoundary>
</React.StrictMode>, </React.StrictMode>,
) )