Переглянути джерело

Add ErrorBoundary component
- wrap a myriad of components in ErrorBoundary

resolves #270

Jason Fischer 2 роки тому
батько
коміт
962e6e576c

+ 2 - 1
src/components/bookmarks/group.jsx

@@ -1,10 +1,11 @@
+import ErrorBoundary from "components/errorboundry";
 import List from "components/bookmarks/list";
 import List from "components/bookmarks/list";
 
 
 export default function BookmarksGroup({ group }) {
 export default function BookmarksGroup({ group }) {
   return (
   return (
     <div key={group.name} className="basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4 flex-1 p-1">
     <div key={group.name} className="basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4 flex-1 p-1">
       <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{group.name}</h2>
       <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{group.name}</h2>
-      <List bookmarks={group.bookmarks} />
+      <ErrorBoundary><List bookmarks={group.bookmarks} /></ErrorBoundary>
     </div>
     </div>
   );
   );
 }
 }

+ 41 - 0
src/components/errorboundry.jsx

@@ -0,0 +1,41 @@
+import React from 'react';
+
+export default class ErrorBoundary extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { error: null, errorInfo: null };
+  }
+
+  componentDidCatch(error, errorInfo) {
+    // Catch errors in any components below and re-render with error message
+    this.setState({
+      error,
+      errorInfo
+    })
+
+    // You can also log error messages to an error reporting service here
+    // eslint-disable-next-line no-console
+    console.error(error, errorInfo);
+  }
+
+  render() {
+    const { error, errorInfo } = this.state;
+    if (errorInfo) {
+      // Error path
+      return (
+        <div>
+          <h2>Something went wrong.</h2>
+          <details style={{ whiteSpace: 'pre-wrap' }}>
+            {error && error.toString()}
+            <br />
+            {errorInfo.componentStack}
+          </details>
+        </div>
+      );
+    }
+
+    // Normally, just render children
+    const { children } = this.props;
+    return children;
+  }
+}

+ 2 - 1
src/components/services/group.jsx

@@ -1,5 +1,6 @@
 import classNames from "classnames";
 import classNames from "classnames";
 
 
+import ErrorBoundary from "components/errorboundry";
 import List from "components/services/list";
 import List from "components/services/list";
 
 
 export default function ServicesGroup({ services, layout }) {
 export default function ServicesGroup({ services, layout }) {
@@ -12,7 +13,7 @@ export default function ServicesGroup({ services, layout }) {
       )}
       )}
     >
     >
       <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{services.name}</h2>
       <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{services.name}</h2>
-      <List services={services.services} layout={layout} />
+      <ErrorBoundary><List services={services.services} layout={layout} /></ErrorBoundary>
     </div>
     </div>
   );
   );
 }
 }

+ 2 - 1
src/components/services/list.jsx

@@ -1,5 +1,6 @@
 import classNames from "classnames";
 import classNames from "classnames";
 
 
+import ErrorBoundary from "components/errorboundry";
 import Item from "components/services/item";
 import Item from "components/services/item";
 
 
 const columnMap = [
 const columnMap = [
@@ -23,7 +24,7 @@ export default function List({ services, layout }) {
       )}
       )}
     >
     >
       {services.map((service) => (
       {services.map((service) => (
-        <Item key={service.name} service={service} />
+        <ErrorBoundary key={service.name}><Item key={service.name} service={service} /></ErrorBoundary>
       ))}
       ))}
     </ul>
     </ul>
   );
   );

+ 5 - 4
src/pages/index.jsx

@@ -8,6 +8,7 @@ import { useEffect, useContext, useState } from "react";
 import { BiError } from "react-icons/bi";
 import { BiError } from "react-icons/bi";
 import { serverSideTranslations } from "next-i18next/serverSideTranslations";
 import { serverSideTranslations } from "next-i18next/serverSideTranslations";
 
 
+import ErrorBoundary from "components/errorboundry";
 import ServicesGroup from "components/services/group";
 import ServicesGroup from "components/services/group";
 import BookmarksGroup from "components/bookmarks/group";
 import BookmarksGroup from "components/bookmarks/group";
 import Widget from "components/widgets/widget";
 import Widget from "components/widgets/widget";
@@ -191,14 +192,14 @@ function Home({ initialSettings }) {
               {widgets
               {widgets
                 .filter((widget) => !rightAlignedWidgets.includes(widget.type))
                 .filter((widget) => !rightAlignedWidgets.includes(widget.type))
                 .map((widget, i) => (
                 .map((widget, i) => (
-                  <Widget key={i} widget={widget} />
+                  <ErrorBoundary key={i}><Widget key={i} widget={widget} /></ErrorBoundary>
                 ))}
                 ))}
 
 
               <div className="ml-4 flex flex-wrap basis-full grow sm:basis-auto justify-between md:justify-end mt-2 md:mt-0">
               <div className="ml-4 flex flex-wrap basis-full grow sm:basis-auto justify-between md:justify-end mt-2 md:mt-0">
                 {widgets
                 {widgets
                   .filter((widget) => rightAlignedWidgets.includes(widget.type))
                   .filter((widget) => rightAlignedWidgets.includes(widget.type))
                   .map((widget, i) => (
                   .map((widget, i) => (
-                    <Widget key={i} widget={widget} />
+                    <ErrorBoundary key={i}><Widget key={i} widget={widget} /></ErrorBoundary>
                   ))}
                   ))}
               </div>
               </div>
             </>
             </>
@@ -208,7 +209,7 @@ function Home({ initialSettings }) {
         {services && (
         {services && (
           <div className="flex flex-wrap p-8 items-start">
           <div className="flex flex-wrap p-8 items-start">
             {services.map((group) => (
             {services.map((group) => (
-              <ServicesGroup key={group.name} services={group} layout={initialSettings.layout?.[group.name]} />
+              <ErrorBoundary key={group.name}><ServicesGroup key={group.name} services={group} layout={initialSettings.layout?.[group.name]} /></ErrorBoundary>
             ))}
             ))}
           </div>
           </div>
         )}
         )}
@@ -216,7 +217,7 @@ function Home({ initialSettings }) {
         {bookmarks && (
         {bookmarks && (
           <div className="grow flex flex-wrap pt-0 p-8">
           <div className="grow flex flex-wrap pt-0 p-8">
             {bookmarks.map((group) => (
             {bookmarks.map((group) => (
-              <BookmarksGroup key={group.name} group={group} />
+              <ErrorBoundary key={group.name}><BookmarksGroup key={group.name} group={group} /></ErrorBoundary>
             ))}
             ))}
           </div>
           </div>
         )}
         )}