refactor(client): Embed error boundary into `AppRoot` (#28393)

pull/28402/head^2
Tasso Evangelista 3 years ago committed by GitHub
parent e4bfde3cfc
commit 262dcaa6dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/meteor/.eslintcache
  2. 18
      apps/meteor/client/components/root/ErrorBoundary.tsx
  3. 15
      apps/meteor/client/startup/appRoot.tsx
  4. 4
      apps/meteor/client/views/banners/BannerRegion.tsx
  5. 23
      apps/meteor/client/views/root/AppErrorPage.tsx
  6. 7
      apps/meteor/client/views/root/AppRoot.tsx
  7. 46
      apps/meteor/client/views/root/OutermostErrorBoundary.tsx

File diff suppressed because one or more lines are too long

@ -1,18 +0,0 @@
import Bugsnag from '@bugsnag/js';
import BugsnagPluginReact from '@bugsnag/plugin-react';
import type { ReactElement } from 'react';
import React, { Fragment } from 'react';
import pkg from '../../../package.json';
const ErrorBoundary = Bugsnag.getPlugin('react')?.createErrorBoundary(React) || Fragment;
Bugsnag.start({
apiKey: (window as any).__BUGSNAG_KEY__,
appVersion: pkg.version,
plugins: [new BugsnagPluginReact()],
});
const BugsnagErrorBoundary = ({ children }: { children: ReactElement }): ReactElement => <ErrorBoundary>{children}</ErrorBoundary>;
export default BugsnagErrorBoundary;

@ -1,10 +1,8 @@
import React, { lazy, Suspense } from 'react';
import React, { StrictMode } from 'react';
import { render } from 'react-dom';
import AppRoot from '../views/root/AppRoot';
import PageLoading from '../views/root/PageLoading';
const Root = lazy(() => import('../components/root/ErrorBoundary'));
const createContainer = (): Element => {
const container = document.getElementById('react-root');
@ -18,15 +16,10 @@ const createContainer = (): Element => {
};
const container = createContainer();
render(
(window as any).__BUGSNAG_KEY__ ? (
<Suspense fallback={<PageLoading />}>
<Root>
<AppRoot />
</Root>
</Suspense>
) : (
<StrictMode>
<AppRoot />
),
</StrictMode>,
container,
);

@ -1,4 +1,4 @@
import type { FC } from 'react';
import type { ReactElement } from 'react';
import React from 'react';
import { useSyncExternalStore } from 'use-sync-external-store/shim';
@ -6,7 +6,7 @@ import * as banners from '../../lib/banners';
import LegacyBanner from './LegacyBanner';
import UiKitBanner from './UiKitBanner';
const BannerRegion: FC = () => {
const BannerRegion = (): ReactElement | null => {
const payload = useSyncExternalStore(...banners.firstSubscription);
if (!payload) {

@ -0,0 +1,23 @@
import { Box, States, StatesIcon, StatesSubtitle, StatesTitle } from '@rocket.chat/fuselage';
import type { ErrorInfo, ReactElement } from 'react';
import React from 'react';
type AppErrorPageProps = {
error: Error;
info?: ErrorInfo;
clearError: () => void;
};
const AppErrorPage = (_props: AppErrorPageProps): ReactElement => {
return (
<Box display='flex' justifyContent='center' height='full' backgroundColor='surface'>
<States>
<StatesIcon name='error-circle' />
<StatesTitle>Application Error</StatesTitle>
<StatesSubtitle>The application GUI just crashed.</StatesSubtitle>
</States>
</Box>
);
};
export default AppErrorPage;

@ -1,8 +1,9 @@
import { QueryClientProvider } from '@tanstack/react-query';
import type { ReactElement } from 'react';
import React, { StrictMode, lazy, Suspense } from 'react';
import React, { lazy, Suspense } from 'react';
import { queryClient } from '../../lib/queryClient';
import OutermostErrorBoundary from './OutermostErrorBoundary';
import PageLoading from './PageLoading';
const ConnectionStatusBar = lazy(() => import('../../components/connectionStatus/ConnectionStatusBar'));
@ -13,7 +14,7 @@ const PortalsWrapper = lazy(() => import('./PortalsWrapper'));
const ModalRegion = lazy(() => import('../modal/ModalRegion'));
const AppRoot = (): ReactElement => (
<StrictMode>
<OutermostErrorBoundary>
<Suspense fallback={<PageLoading />}>
<QueryClientProvider client={queryClient}>
<MeteorProvider>
@ -25,7 +26,7 @@ const AppRoot = (): ReactElement => (
</MeteorProvider>
</QueryClientProvider>
</Suspense>
</StrictMode>
</OutermostErrorBoundary>
);
export default AppRoot;

@ -0,0 +1,46 @@
import Bugsnag from '@bugsnag/js';
import type { BugsnagErrorBoundary as BugsnagErrorBoundaryComponent } from '@bugsnag/plugin-react';
import BugsnagPluginReact from '@bugsnag/plugin-react';
import type { ReactNode } from 'react';
import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Info } from '../../../app/utils/client';
import AppErrorPage from './AppErrorPage';
declare global {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface Window {
__BUGSNAG_KEY__: string;
}
}
let BugsnagErrorBoundary: BugsnagErrorBoundaryComponent | undefined;
if (window.__BUGSNAG_KEY__) {
Bugsnag.start({
apiKey: window.__BUGSNAG_KEY__,
appVersion: Info.version,
plugins: [new BugsnagPluginReact()],
});
BugsnagErrorBoundary = Bugsnag.getPlugin('react')?.createErrorBoundary(React);
}
type OutermostErrorBoundaryProps = {
children: ReactNode;
};
const OutermostErrorBoundary = ({ children }: OutermostErrorBoundaryProps) => {
if (BugsnagErrorBoundary) {
return <BugsnagErrorBoundary FallbackComponent={AppErrorPage}>{children}</BugsnagErrorBoundary>;
}
return (
<ErrorBoundary fallbackRender={({ error, resetErrorBoundary }) => <AppErrorPage error={error} clearError={resetErrorBoundary} />}>
{children}
</ErrorBoundary>
);
};
export default OutermostErrorBoundary;
Loading…
Cancel
Save