From 8cfae8422013dbf62da541a5645a656f29146d6a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 10 Jul 2023 15:56:39 +0200 Subject: [PATCH] ErrorBoundary: include service worker state (#398) --- src/App.jsx | 10 ++-- src/components/ErrorFallback.jsx | 92 ++++++++++++++++++++++++++++++++ src/components/explorer.jsx | 88 ++++-------------------------- 3 files changed, 110 insertions(+), 80 deletions(-) create mode 100644 src/components/ErrorFallback.jsx diff --git a/src/App.jsx b/src/App.jsx index 9202fb12a..4a2ecd853 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -15,6 +15,8 @@ import { getZoom, getClipsNav } from './url'; import { isDemo } from './demo'; import store, { history } from './store'; +import ErrorFallback from './components/ErrorFallback'; + const Explorer = lazy(() => import('./components/explorer')); const AnonymousLanding = lazy(() => import('./components/anonymous')); @@ -120,9 +122,11 @@ class App extends Component { return ( - - { showLogin ? this.anonymousRoutes() : this.authRoutes() } - + }> + + { showLogin ? this.anonymousRoutes() : this.authRoutes() } + + ); diff --git a/src/components/ErrorFallback.jsx b/src/components/ErrorFallback.jsx new file mode 100644 index 000000000..54f8eeb1b --- /dev/null +++ b/src/components/ErrorFallback.jsx @@ -0,0 +1,92 @@ +import { useEffect, useRef, useState } from 'react'; + +import { Check, ContentCopy } from '../icons'; + +const ErrorFallback = ({ error, componentStack }) => { + const [swInfo, setSwInfo] = useState(''); + const [copied, setCopied] = useState(false); + const copiedInterval = useRef(null); + + console.log({ error, componentStack }); + + useEffect(() => { + if ('serviceWorker' in navigator) { + setSwInfo('loading...'); + navigator.serviceWorker.getRegistrations().then((registrations) => { + if (registrations.length === 0) { + setSwInfo('none'); + return; + } + const serviceWorkers = []; + for (const registration of registrations) { + serviceWorkers.push(`${registration.scope} ${registration.active?.state}`); + } + setSwInfo(serviceWorkers.join('; ')); + }).catch((err) => { + setSwInfo(err.toString()); + }); + } else { + setSwInfo('not supported'); + } + }, []); + + const information = `connect version: ${import.meta.env.VITE_APP_GIT_SHA || 'unknown'} +Build timestamp: ${import.meta.env.VITE_APP_BUILD_TIMESTAMP || 'unknown'} +URL: ${window.location.href} + +Browser: ${window.navigator.userAgent} +Window: ${window.innerWidth}x${window.innerHeight} + +Service workers: ${swInfo} + +${error.toString()}${componentStack}`; + + const copyError = async () => { + if (copiedInterval.current) { + clearTimeout(copiedInterval.current); + } + try { + await navigator.clipboard.writeText('```' + information + '```'); + setCopied(true); + copiedInterval.current = setTimeout(() => setCopied(false), 2000); + } catch (err) { + console.error('Failed to copy:', err); + } + }; + + return ( +
+
+

Oops!

+

Something went wrong. Please reload the page.

+

+ If you continue to have problems, let us know on Discord{` `} + in the #connect-feedback channel. +

+

+ + Reload + +

+
+
+ Show debugging information +
+
+            {information}
+          
+ +
+
+
+ ); +}; + +export default ErrorFallback; diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 5edb599a6..14726b561 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -1,4 +1,4 @@ -import React, { Component, lazy, Suspense, useMemo, useRef, useState } from 'react'; +import React, { Component, lazy, Suspense } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; import localforage from 'localforage'; @@ -17,12 +17,11 @@ import AppDrawer from './AppDrawer'; import PullDownReload from './utils/PullDownReload'; import { analyticsEvent, selectDevice, updateDevice } from '../actions'; -import ResizeHandler from './ResizeHandler'; +import init from '../actions/startup'; import Colors from '../colors'; -import { Check, ContentCopy } from '../icons'; import { verifyPairToken, pairErrorToMessage } from '../utils'; import { play, pause } from '../timeline/playback'; -import init from '../actions/startup'; +import ResizeHandler from './ResizeHandler'; const ClipView = lazy(() => import('./ClipView')); const DriveView = lazy(() => import('./DriveView')); @@ -62,69 +61,6 @@ const styles = (theme) => ({ }, }); -const ErrorFallback = ({ error, componentStack }) => { - const [copied, setCopied] = useState(false); - const copiedInterval = useRef(null); - - const version = import.meta.env.VITE_APP_GIT_SHA || 'unknown'; - const userAgent = window.navigator.userAgent; - const platform = window.navigator.platform; - - const information = useMemo(() => `connect version: ${version} -URL: ${window.location.href} - -Device: ${platform} -Browser: ${userAgent} -Window: ${window.innerWidth}x${window.innerHeight} - -${error.toString()}${componentStack}`, [version, userAgent, platform, error, componentStack]); - - const copyError = async () => { - if (copiedInterval.current) { - clearTimeout(copiedInterval.current); - } - try { - await navigator.clipboard.writeText('```' + information + '```'); - setCopied(true); - copiedInterval.current = setTimeout(() => setCopied(false), 2000); - } catch (err) { - console.error('Failed to copy:', err); - } - }; - - return ( -
-

Oops!

-

Something went wrong. Please reload the page.

-

- If you continue to have problems, let us know on Discord{` `} - in the #connect-feedback channel. -

-

- - Reload - -

-
- Show debugging information -
-
-            {information}
-          
- -
-
-
- ); -}; - class ExplorerApp extends Component { constructor(props) { super(props); @@ -291,16 +227,14 @@ class ExplorerApp extends Component { style={ drawerStyles } />
- }> - - { noDevicesUpsell - ? - : (clips - ? - : (zoom ? : ) - ) } - - + + { noDevicesUpsell + ? + : (clips + ? + : (zoom ? : ) + ) } +