Skip to content

Commit f0f8a36

Browse files
authored
Added fallback error page for unhandled errors in stats app (#24382)
ref https://linear.app/ghost/issue/PROD-2313/fix-fallback-error-page-for-unhandled-errors-in-the-stats-app There is currently a bug in the stats app that throws an error from the GlobalDataProvider, before the app has fully rendered. This error is preventing the whole app from loading, and instead it is falling back to this very unfriendly error page: <img width="1421" height="474" alt="image" src="https://github.com/user-attachments/assets/baefda11-7edd-4bb9-8873-47c8b4d5a467" /> The fix for that error is irrelevant to this PR — it will be fixed in a separate PR. This PR is strictly to add a fallback error page for any unhandled errors in the stats app, so no user ever sees the abomination above. For now this adds the same exact fallback error handler that is used for all the `admin-x-` apps, defined in the Ember admin-x-component file. <img width="867" height="692" alt="image" src="https://github.com/user-attachments/assets/0f80c13d-6222-45df-8626-93f0e6a8fd62" />
1 parent 792bf79 commit f0f8a36

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

apps/stats/src/App.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import GlobalDataProvider from './providers/GlobalDataProvider';
2+
import StatsErrorBoundary from './components/errors/StatsErrorBoundary';
23
import {APP_ROUTE_PREFIX, routes} from '@src/routes';
34
import {AppProvider, BaseAppProps, FrameworkProvider, Outlet, RouterProvider} from '@tryghost/admin-x-framework';
45
import {ShadeApp} from '@tryghost/shade';
@@ -17,11 +18,13 @@ const App: React.FC<BaseAppProps> = ({framework, designSystem, appSettings}) =>
1718
>
1819
<AppProvider appSettings={appSettings}>
1920
<RouterProvider prefix={APP_ROUTE_PREFIX} routes={routes}>
20-
<GlobalDataProvider>
21-
<ShadeApp className="shade-stats" darkMode={designSystem.darkMode} fetchKoenigLexical={null}>
22-
<Outlet />
23-
</ShadeApp>
24-
</GlobalDataProvider>
21+
<StatsErrorBoundary>
22+
<GlobalDataProvider>
23+
<ShadeApp className="shade-stats" darkMode={designSystem.darkMode} fetchKoenigLexical={null}>
24+
<Outlet />
25+
</ShadeApp>
26+
</GlobalDataProvider>
27+
</StatsErrorBoundary>
2528
</RouterProvider>
2629
</AppProvider>
2730
</FrameworkProvider>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import StatsErrorPage from './StatsErrorPage';
3+
4+
class StatsErrorBoundary extends React.Component<{children: React.ReactNode}, {hasError: boolean, error?: Error}> {
5+
constructor(props: {children: React.ReactNode}) {
6+
super(props);
7+
this.state = {hasError: false};
8+
}
9+
10+
static getDerivedStateFromError(error: Error) {
11+
return {hasError: true, error};
12+
}
13+
14+
render() {
15+
if (this.state.hasError) {
16+
return <StatsErrorPage error={this.state.error} />;
17+
}
18+
return this.props.children;
19+
}
20+
}
21+
22+
export default StatsErrorBoundary;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
3+
interface StatsErrorPageProps {
4+
error?: Error;
5+
}
6+
7+
const StatsErrorPage: React.FC<StatsErrorPageProps> = () => {
8+
return (
9+
<div className="admin-x-container-error">
10+
<div className="admin-x-error">
11+
<h1>Loading interrupted</h1>
12+
<p>They say life is a series of trials and tribulations. This moment right here? It&apos;s a tribulation. Our app was supposed to load, and yet here we are. Loadless. Click back to the dashboard to try again.</p>
13+
<a className="cursor-pointer" onClick={() => window.location.reload()}>&larr; Back to the dashboard</a>
14+
</div>
15+
</div>
16+
);
17+
};
18+
19+
export default StatsErrorPage;

0 commit comments

Comments
 (0)