diff --git a/frontend/src/Components/Error/ErrorBoundaryError.css b/frontend/src/Components/Error/ErrorBoundaryError.css
index b6d1f917e..3e7a04302 100644
--- a/frontend/src/Components/Error/ErrorBoundaryError.css
+++ b/frontend/src/Components/Error/ErrorBoundaryError.css
@@ -25,6 +25,10 @@
white-space: pre-wrap;
}
+.version {
+ margin-top: 20px;
+}
+
@media only screen and (max-width: $breakpointMedium) {
.image {
height: 250px;
diff --git a/frontend/src/Components/Error/ErrorBoundaryError.css.d.ts b/frontend/src/Components/Error/ErrorBoundaryError.css.d.ts
index 1d4e56b65..e19fd804d 100644
--- a/frontend/src/Components/Error/ErrorBoundaryError.css.d.ts
+++ b/frontend/src/Components/Error/ErrorBoundaryError.css.d.ts
@@ -6,6 +6,7 @@ interface CssExports {
'image': string;
'imageContainer': string;
'message': string;
+ 'version': string;
}
export const cssExports: CssExports;
export default cssExports;
diff --git a/frontend/src/Components/Error/ErrorBoundaryError.js b/frontend/src/Components/Error/ErrorBoundaryError.js
deleted file mode 100644
index e0181db96..000000000
--- a/frontend/src/Components/Error/ErrorBoundaryError.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import styles from './ErrorBoundaryError.css';
-
-function ErrorBoundaryError(props) {
- const {
- className,
- messageClassName,
- detailsClassName,
- message,
- error,
- info
- } = props;
-
- return (
-
-
- {message}
-
-
-
-

-
-
-
- {
- error &&
-
- {error.toString()}
-
- }
-
-
- {info.componentStack}
-
-
-
- );
-}
-
-ErrorBoundaryError.propTypes = {
- className: PropTypes.string.isRequired,
- messageClassName: PropTypes.string.isRequired,
- detailsClassName: PropTypes.string.isRequired,
- message: PropTypes.string.isRequired,
- error: PropTypes.object.isRequired,
- info: PropTypes.object.isRequired
-};
-
-ErrorBoundaryError.defaultProps = {
- className: styles.container,
- messageClassName: styles.message,
- detailsClassName: styles.details,
- message: 'There was an error loading this content'
-};
-
-export default ErrorBoundaryError;
diff --git a/frontend/src/Components/Error/ErrorBoundaryError.tsx b/frontend/src/Components/Error/ErrorBoundaryError.tsx
new file mode 100644
index 000000000..e19575b47
--- /dev/null
+++ b/frontend/src/Components/Error/ErrorBoundaryError.tsx
@@ -0,0 +1,73 @@
+import React, { useEffect, useState } from 'react';
+import StackTrace from 'stacktrace-js';
+import styles from './ErrorBoundaryError.css';
+
+interface ErrorBoundaryErrorProps {
+ className: string;
+ messageClassName: string;
+ detailsClassName: string;
+ message: string;
+ error: Error;
+ info: {
+ componentStack: string;
+ };
+}
+
+function ErrorBoundaryError(props: ErrorBoundaryErrorProps) {
+ const t1 = 1;
+ const t2 = 2;
+
+ const {
+ className = styles.container,
+ messageClassName = styles.message,
+ detailsClassName = styles.details,
+ message = 'There was an error loading this content',
+ error,
+ info,
+ } = props;
+
+ const [detailedError, setDetailedError] = useState(null);
+
+ useEffect(() => {
+ if (error) {
+ StackTrace.fromError(error).then((de) => {
+ setDetailedError(de);
+ });
+ } else {
+ setDetailedError(null);
+ }
+ }, [error, setDetailedError]);
+
+ return (
+
+
{message}
+
+
+

+
+
+
+ {error ? {error.message}
: null}
+
+ {detailedError ? (
+ detailedError.map((d, index) => {
+ return (
+
+ {` at ${d.functionName} (${d.fileName}:${d.lineNumber}:${d.columnNumber})`}
+
+ );
+ })
+ ) : (
+ {info.componentStack}
+ )}
+
+ {Version: {window.Sonarr.version}
}
+
+
+ );
+}
+
+export default ErrorBoundaryError;
diff --git a/frontend/typings/Globals.d.ts b/frontend/typings/Globals.d.ts
index 60260a3ad..d11f99013 100644
--- a/frontend/typings/Globals.d.ts
+++ b/frontend/typings/Globals.d.ts
@@ -1 +1,11 @@
declare module '*.module.css';
+
+interface Window {
+ Sonarr: {
+ apiKey: string;
+ instanceName: string;
+ theme: string;
+ urlBase: string;
+ version: string;
+ };
+}
diff --git a/package.json b/package.json
index 75ea581df..3d6dd5068 100644
--- a/package.json
+++ b/package.json
@@ -85,6 +85,7 @@
"redux-localstorage": "0.4.1",
"redux-thunk": "2.4.1",
"reselect": "4.1.5",
+ "stacktrace-js": "2.0.2",
"typescript": "4.9.4"
},
"devDependencies": {
diff --git a/yarn.lock b/yarn.lock
index c7be12c32..76090bb5a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2974,6 +2974,13 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
+error-stack-parser@^2.0.6:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286"
+ integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==
+ dependencies:
+ stackframe "^1.3.4"
+
error@^7.0.0:
version "7.2.1"
resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894"
@@ -6329,6 +6336,11 @@ source-map-support@~0.5.20:
buffer-from "^1.0.0"
source-map "^0.6.0"
+source-map@0.5.6:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+ integrity sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==
+
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@@ -6370,6 +6382,13 @@ specificity@^0.4.1:
resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019"
integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==
+stack-generator@^2.0.5:
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.10.tgz#8ae171e985ed62287d4f1ed55a1633b3fb53bb4d"
+ integrity sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==
+ dependencies:
+ stackframe "^1.3.4"
+
stack-utils@^2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f"
@@ -6377,6 +6396,28 @@ stack-utils@^2.0.3:
dependencies:
escape-string-regexp "^2.0.0"
+stackframe@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310"
+ integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==
+
+stacktrace-gps@^3.0.4:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz#0c40b24a9b119b20da4525c398795338966a2fb0"
+ integrity sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==
+ dependencies:
+ source-map "0.5.6"
+ stackframe "^1.3.4"
+
+stacktrace-js@2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b"
+ integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==
+ dependencies:
+ error-stack-parser "^2.0.6"
+ stack-generator "^2.0.5"
+ stacktrace-gps "^3.0.4"
+
stdin@*:
version "0.0.1"
resolved "https://registry.yarnpkg.com/stdin/-/stdin-0.0.1.tgz#d3041981aaec3dfdbc77a1b38d6372e38f5fb71e"