diff --git a/src/qqq/components/misc/ErrorBoundary.tsx b/src/qqq/components/misc/ErrorBoundary.tsx new file mode 100644 index 0000000..c4e27e9 --- /dev/null +++ b/src/qqq/components/misc/ErrorBoundary.tsx @@ -0,0 +1,74 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import React, {Component, ErrorInfo} from "react"; + +interface Props +{ + errorElement?: React.ReactNode; + children: React.ReactNode; +} + +interface State +{ + hasError: boolean; +} + +/******************************************************************************* + ** Component that you can wrap around other components that might throw an error, + ** to give some isolation, rather than breaking a whole page. + ** Credit: https://medium.com/@bobjunior542/how-to-use-error-boundaries-in-react-js-with-typescript-ee90ec814bf1 + *******************************************************************************/ +class ErrorBoundary extends Component +{ + /*************************************************************************** + * + ***************************************************************************/ + constructor(props: Props) + { + super(props); + this.state = {hasError: false}; + } + + /*************************************************************************** + * + ***************************************************************************/ + componentDidCatch(error: Error, errorInfo: ErrorInfo) + { + console.error("ErrorBoundary caught an error: ", error, errorInfo); + this.setState({hasError: true}); + } + + /*************************************************************************** + * + ***************************************************************************/ + render() + { + if (this.state.hasError) + { + return this.props.errorElement ?? (Error); + } + + return this.props.children; + } +} + +export default ErrorBoundary; \ No newline at end of file diff --git a/src/qqq/components/misc/HelpContent.tsx b/src/qqq/components/misc/HelpContent.tsx index f66f13d..34e7aec 100644 --- a/src/qqq/components/misc/HelpContent.tsx +++ b/src/qqq/components/misc/HelpContent.tsx @@ -22,6 +22,7 @@ import {QHelpContent} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QHelpContent"; import Box from "@mui/material/Box"; import parse from "html-react-parser"; +import ErrorBoundary from "qqq/components/misc/ErrorBoundary"; import React, {useContext} from "react"; import Markdown from "react-markdown"; import QContext from "QContext"; @@ -128,6 +129,7 @@ function HelpContent({helpContents, roles, heading, helpContentKey}: Props): JSX let selectedHelpContent = getMatchingHelpContent(helpContentsArray, roles); let content = null; + let errorContent = "Error rendering help content."; if (helpHelpActive) { if (!selectedHelpContent) @@ -135,6 +137,7 @@ function HelpContent({helpContents, roles, heading, helpContentKey}: Props): JSX selectedHelpContent = new QHelpContent({content: ""}); } content = selectedHelpContent.content + ` [${helpContentKey ?? "?"}]`; + errorContent += ` [${helpContentKey ?? "?"}]`; } else if(selectedHelpContent) { @@ -148,7 +151,9 @@ function HelpContent({helpContents, roles, heading, helpContentKey}: Props): JSX { return {heading && {heading}} - {formatHelpContent(content, selectedHelpContent.format)} + {errorContent}}> + {formatHelpContent(content, selectedHelpContent.format)} + ; }