diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index ddb3a3a0d..f0a40a452 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -26,6 +26,7 @@ "react": "^18.2.0", "react-cookie": "^4.1.1", "react-dom": "^18.2.0", + "react-error-boundary": "^4.0.2", "react-icons": "^4.7.1", "react-laag": "^2.0.5", "react-router-dom": "^6.8.1", @@ -14960,6 +14961,17 @@ "react": "^18.2.0" } }, + "node_modules/react-error-boundary": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.2.tgz", + "integrity": "sha512-/h21OS80hQ1m/s5UVOp1JKkC8XmUo0rOTRUliGSmWtvswkbbijuQ074K0QLEHwxwwesTt7ksR74/9EHImqWo+A==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", diff --git a/src/frontend/package.json b/src/frontend/package.json index 15aa1e48b..312e52051 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -21,6 +21,7 @@ "react": "^18.2.0", "react-cookie": "^4.1.1", "react-dom": "^18.2.0", + "react-error-boundary": "^4.0.2", "react-icons": "^4.7.1", "react-laag": "^2.0.5", "react-router-dom": "^6.8.1", diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index f0944be3f..0e5f1887d 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -9,6 +9,9 @@ import ExtraSidebar from "./components/ExtraSidebarComponent"; import { alertContext } from "./contexts/alertContext"; import { locationContext } from "./contexts/locationContext"; import TabsManagerComponent from "./pages/FlowPage/components/tabsManagerComponent"; +import { ErrorBoundary } from "react-error-boundary"; +import CrashErrorComponent from "./components/CrashErrorComponent"; +import { TabsContext } from "./contexts/tabsContext"; export default function App() { var _ = require("lodash"); @@ -21,7 +24,7 @@ export default function App() { setShowSideBar(true); setIsStackedOpen(true); }, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]); - + const {hardReset} = useContext(TabsContext) const { errorData, errorOpen, @@ -34,45 +37,62 @@ export default function App() { setSuccessOpen, } = useContext(alertContext); -// Initialize state variable for the list of alerts -const [alertsList, setAlertsList] = useState,link?:string},id:string}>>([]); + // Initialize state variable for the list of alerts + const [alertsList, setAlertsList] = useState< + Array<{ + type: string; + data: { title: string; list?: Array; link?: string }; + id: string; + }> + >([]); -// Use effect hook to update alertsList when a new alert is added -useEffect(() => { - // If there is an error alert open with data, add it to the alertsList - if (errorOpen && errorData) { - setErrorOpen(false); - setAlertsList((old) => { - let newAlertsList = [ - ...old, - { type: "error", data: _.cloneDeep(errorData), id: _.uniqueId() }, - ]; - return newAlertsList; - }); - } - // If there is a notice alert open with data, add it to the alertsList - else if (noticeOpen && noticeData) { - setNoticeOpen(false); - setAlertsList((old) => { - let newAlertsList = [ - ...old, - { type: "notice", data: _.cloneDeep(noticeData), id: _.uniqueId() }, - ]; - return newAlertsList; - }); - } - // If there is a success alert open with data, add it to the alertsList - else if (successOpen && successData) { - setSuccessOpen(false); - setAlertsList((old) => { - let newAlertsList = [ - ...old, - { type: "success", data: _.cloneDeep(successData), id: _.uniqueId() }, - ]; - return newAlertsList; - }); - } -}, [_, errorData, errorOpen, noticeData, noticeOpen, setErrorOpen, setNoticeOpen, setSuccessOpen, successData, successOpen]); + // Use effect hook to update alertsList when a new alert is added + useEffect(() => { + // If there is an error alert open with data, add it to the alertsList + if (errorOpen && errorData) { + setErrorOpen(false); + setAlertsList((old) => { + let newAlertsList = [ + ...old, + { type: "error", data: _.cloneDeep(errorData), id: _.uniqueId() }, + ]; + return newAlertsList; + }); + } + // If there is a notice alert open with data, add it to the alertsList + else if (noticeOpen && noticeData) { + setNoticeOpen(false); + setAlertsList((old) => { + let newAlertsList = [ + ...old, + { type: "notice", data: _.cloneDeep(noticeData), id: _.uniqueId() }, + ]; + return newAlertsList; + }); + } + // If there is a success alert open with data, add it to the alertsList + else if (successOpen && successData) { + setSuccessOpen(false); + setAlertsList((old) => { + let newAlertsList = [ + ...old, + { type: "success", data: _.cloneDeep(successData), id: _.uniqueId() }, + ]; + return newAlertsList; + }); + } + }, [ + _, + errorData, + errorOpen, + noticeData, + noticeOpen, + setErrorOpen, + setNoticeOpen, + setSuccessOpen, + successData, + successOpen, + ]); const removeAlert = (id: string) => { setAlertsList((prevAlertsList) => @@ -83,18 +103,27 @@ useEffect(() => { return ( //need parent component with width and height
-
-
-
- - {/* Main area */} -
- {/* Primary column */} -
- -
-
-
+
+ { + window.localStorage.removeItem("tabsData"); + window.localStorage.clear(); + hardReset() + window.location.href = window.location.href; + }} + FallbackComponent={CrashErrorComponent} + > +
+ + {/* Main area */} +
+ {/* Primary column */} +
+ +
+
+
+
{alertsList.map((alert) => ( @@ -126,7 +155,13 @@ useEffect(() => {
))}
- Created by Logspace + + Created by Logspace + ); } diff --git a/src/frontend/src/components/CrashErrorComponent/index.tsx b/src/frontend/src/components/CrashErrorComponent/index.tsx new file mode 100644 index 000000000..7864e6d65 --- /dev/null +++ b/src/frontend/src/components/CrashErrorComponent/index.tsx @@ -0,0 +1,31 @@ +export default function CrashErrorComponent({ error, resetErrorBoundary }) { + return ( +
+
+

Oops! An unknown error has occurred.

+

+ Please click the 'Reset Application' button + to restore the application's state. If the error persists, please + create an issue on our GitHub page. We apologize for any inconvenience + this may have caused. +

+
+ + + Create Issue + +
+
+
+ ); +} diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index ae5833442..10c0b943e 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -15,7 +15,8 @@ const TabsContextInitialValue: TabsContextType = { downloadFlow: (flow:FlowType) => {}, uploadFlow: () => {}, lockChat: false, - setLockChat:(prevState:boolean)=>{} + setLockChat:(prevState:boolean)=>{}, + hardReset:()=>{} }; export const TabsContext = createContext( @@ -54,6 +55,10 @@ export function TabsProvider({ children }: { children: ReactNode }) { newNodeId.current = cookieObject.nodeId; } }, []); + function hardReset(){ + newNodeId.current=0; + setTabIndex(0);setFlows([]);setId(0); + } /** * Downloads the current flow as a JSON file @@ -172,6 +177,7 @@ export function TabsProvider({ children }: { children: ReactNode }) { return ( - - - - + + + + + + ); reportWebVitals(); diff --git a/src/frontend/src/modals/importModal/buttonBox/index.tsx b/src/frontend/src/modals/importModal/buttonBox/index.tsx index 38d2e84bf..084981adc 100644 --- a/src/frontend/src/modals/importModal/buttonBox/index.tsx +++ b/src/frontend/src/modals/importModal/buttonBox/index.tsx @@ -9,6 +9,7 @@ export default function ButtonBox({ icon, bgColor, textColor, + deactivate }: { onClick: () => void; title: string; @@ -16,9 +17,10 @@ export default function ButtonBox({ icon: ReactNode; bgColor: string; textColor: string; + deactivate?:boolean; }) { return ( -