error handling with hard reset
This commit is contained in:
parent
11c53d6338
commit
5f7be7d1a5
9 changed files with 163 additions and 71 deletions
12
src/frontend/package-lock.json
generated
12
src/frontend/package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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<Array<{type:string,data:{title:string,list?:Array<string>,link?:string},id:string}>>([]);
|
||||
// Initialize state variable for the list of alerts
|
||||
const [alertsList, setAlertsList] = useState<
|
||||
Array<{
|
||||
type: string;
|
||||
data: { title: string; list?: Array<string>; 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
|
||||
<div className="h-full flex flex-col">
|
||||
<div className="flex grow-0 shrink basis-auto">
|
||||
</div>
|
||||
<div className="flex grow shrink basis-auto min-h-0 flex-1 overflow-hidden">
|
||||
<ExtraSidebar />
|
||||
{/* Main area */}
|
||||
<main className="min-w-0 flex-1 border-t border-gray-200 dark:border-gray-700 flex">
|
||||
{/* Primary column */}
|
||||
<div className="w-full h-full">
|
||||
<TabsManagerComponent></TabsManagerComponent>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div className="flex grow-0 shrink basis-auto"></div>
|
||||
<ErrorBoundary
|
||||
onReset={() => {
|
||||
window.localStorage.removeItem("tabsData");
|
||||
window.localStorage.clear();
|
||||
hardReset()
|
||||
window.location.href = window.location.href;
|
||||
}}
|
||||
FallbackComponent={CrashErrorComponent}
|
||||
>
|
||||
<div className="flex grow shrink basis-auto min-h-0 flex-1 overflow-hidden">
|
||||
<ExtraSidebar />
|
||||
{/* Main area */}
|
||||
<main className="min-w-0 flex-1 border-t border-gray-200 dark:border-gray-700 flex">
|
||||
{/* Primary column */}
|
||||
<div className="w-full h-full">
|
||||
<TabsManagerComponent></TabsManagerComponent>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
<div></div>
|
||||
<div className="flex z-40 flex-col-reverse fixed bottom-5 left-5">
|
||||
{alertsList.map((alert) => (
|
||||
|
|
@ -126,7 +155,13 @@ useEffect(() => {
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
<a target={"_blank"} href="https://logspace.ai/" className="absolute bottom-1 left-1 text-gray-500 text-xs cursor-pointer font-sans tracking-wide">Created by Logspace</a>
|
||||
<a
|
||||
target={"_blank"}
|
||||
href="https://logspace.ai/"
|
||||
className="absolute bottom-1 left-1 text-gray-500 text-xs cursor-pointer font-sans tracking-wide"
|
||||
>
|
||||
Created by Logspace
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
31
src/frontend/src/components/CrashErrorComponent/index.tsx
Normal file
31
src/frontend/src/components/CrashErrorComponent/index.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
export default function CrashErrorComponent({ error, resetErrorBoundary }) {
|
||||
return (
|
||||
<div className="fixed top-0 left-0 w-full h-full flex items-center justify-center bg-gray-800 bg-opacity-50 z-50">
|
||||
<div className="bg-white max-w-4xl h-1/3 min-h-fit rounded-lg shadow-lg p-8 text-start flex flex-col justify-evenly">
|
||||
<h1 className="text-red-500 text-3xl mb-4">Oops! An unknown error has occurred.</h1>
|
||||
<p className="text-gray-700 mb-4 text-xl">
|
||||
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.
|
||||
</p>
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
onClick={resetErrorBoundary}
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mr-4"
|
||||
>
|
||||
Reset Application
|
||||
</button>
|
||||
<a
|
||||
href="https://github.com/logspace-ai/langflow/issues/new"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
|
||||
>
|
||||
Create Issue
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -15,7 +15,8 @@ const TabsContextInitialValue: TabsContextType = {
|
|||
downloadFlow: (flow:FlowType) => {},
|
||||
uploadFlow: () => {},
|
||||
lockChat: false,
|
||||
setLockChat:(prevState:boolean)=>{}
|
||||
setLockChat:(prevState:boolean)=>{},
|
||||
hardReset:()=>{}
|
||||
};
|
||||
|
||||
export const TabsContext = createContext<TabsContextType>(
|
||||
|
|
@ -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 (
|
||||
<TabsContext.Provider
|
||||
value={{
|
||||
hardReset,
|
||||
lockChat,
|
||||
setLockChat,
|
||||
tabIndex,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import ContextWrapper from './contexts';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import ContextWrapper from "./contexts";
|
||||
import CrashErrorComponent from "./components/CrashErrorComponent";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
document.getElementById("root") as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<ContextWrapper>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</ContextWrapper>
|
||||
<ContextWrapper>
|
||||
<BrowserRouter>
|
||||
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</ContextWrapper>
|
||||
);
|
||||
reportWebVitals();
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<button onClick={onClick}>
|
||||
<button disabled={deactivate} onClick={onClick}>
|
||||
<div
|
||||
className={classNames(
|
||||
"col-span-1 flex flex-col divide-y divide-gray-200 rounded-lg text-center shadow border border-gray-300 hover:shadow-lg transform hover:scale-105",
|
||||
|
|
@ -36,7 +38,7 @@ export default function ButtonBox({
|
|||
<h3 className="mt-6 text-lg font-semibold text-white">{title}</h3>
|
||||
<div className="mt-1 flex flex-grow flex-col justify-between">
|
||||
<dt className="sr-only">{title}</dt>
|
||||
<dd className="text-sm text-gray-100">{description}</dd>
|
||||
<dd className="text-sm text-gray-100">{deactivate? "cooming soon":description}</dd>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -88,13 +88,14 @@ export default function ImportModal() {
|
|||
<div className="h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
|
||||
<div className="flex h-full w-full justify-evenly items-center">
|
||||
<ButtonBox
|
||||
bgColor="bg-blue-500"
|
||||
deactivate
|
||||
bgColor="bg-slate-400"
|
||||
description="Prebuilt Examples"
|
||||
icon={
|
||||
<DocumentDuplicateIcon className="h-10 w-10 flex-shrink-0" />
|
||||
}
|
||||
onClick={() => console.log("sdsds")}
|
||||
textColor="text-blue-500"
|
||||
textColor="text-slate-400"
|
||||
title="Examples"
|
||||
></ButtonBox>
|
||||
<ButtonBox
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export type TabsContextType = {
|
|||
incrementNodeId: () => number;
|
||||
downloadFlow: (flow:FlowType) => void;
|
||||
uploadFlow: () => void;
|
||||
lockChat:boolean,
|
||||
setLockChat:(prevState:boolean)=>void
|
||||
lockChat:boolean;
|
||||
setLockChat:(prevState:boolean)=>void;
|
||||
hardReset:()=>void;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue