From 496c2aae3eaad72641ab64b01ab7e0610f06f102 Mon Sep 17 00:00:00 2001
From: Cristhian Zanforlin Lousa
<72977554+Cristhianzl@users.noreply.github.com>
Date: Fri, 22 Mar 2024 09:34:59 -0300
Subject: [PATCH] Add a new handle when the backend application is offline
(#1550)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
✨ (App.tsx): Import the `useNavigate` hook from `react-router-dom` to enable programmatic navigation within the app.
📝 (App.tsx): Add comments to explain the purpose of the `isLoadingHealth` state variable and the `checkApplicationHealth` function.
📝 (App.tsx): Add comments to explain the purpose of the `onHealthCheck` function.
🐛 (App.tsx): Fix a bug where the `checkApplicationHealth` function was not being called when the component mounts.
🐛 (App.tsx): Fix a bug where the `onHealthCheck` function was not being called when the health check was successful.
📝 (App.tsx): Add comments to explain the purpose of the `checkApplicationHealth` function and the `onHealthCheck` function.
✨ (fetchErrorComponent/index.tsx): Import the `BaseModal` component from the `modals/baseModal` module to display the fetch error component in a modal.
✨ (fetchErrorComponent/index.tsx): Import the `Button` component from the `ui/button` module to display a retry button in the fetch error component.
✨ (fetchErrorComponent/index.tsx): Add a retry button to the fetch error component to allow the user to retry the failed request.
✨ (ui/dialog-with-no-close.tsx): Create a new file `ui/dialog-with-no-close.tsx` to define a custom dialog component without a close button.
✨ (ui/dialog-with-no-close.tsx): Define the `Dialog`, `DialogTrigger`, `DialogPortal`, `DialogOverlay`, `DialogContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`, and `DialogDescription` components for the custom dialog component.
📝 (baseModal/index.tsx): add support for a new type prop to switch between modal and dialog mode
🐛 (baseModal/index.tsx): fix typo in import statement for Modal and ModalContent components
♻️ (baseModal/index.tsx): refactor BaseModal component to conditionally render either Modal or Dialog based on the type prop
🐛 (flowsManagerStore.ts): fix issue where isLoading state was not being set to false after catching an error
🐛 (typesStore.ts): fix issue where error alert was not being shown when fetching types failed
🐛 (typesStore.ts): remove unnecessary error alert when fetching types failed
✨ (components/index.ts): add new properties to fetchErrorComponentType to support opening a modal, retrying, and showing loading state
---
src/frontend/src/App.tsx | 68 +++++++---
.../components/fetchErrorComponent/index.tsx | 47 ++++++-
.../components/ui/dialog-with-no-close.tsx | 119 ++++++++++++++++++
src/frontend/src/modals/baseModal/index.tsx | 61 ++++++---
src/frontend/src/stores/flowsManagerStore.ts | 1 +
src/frontend/src/stores/typesStore.ts | 4 -
src/frontend/src/types/components/index.ts | 3 +
7 files changed, 262 insertions(+), 41 deletions(-)
create mode 100644 src/frontend/src/components/ui/dialog-with-no-close.tsx
diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx
index be45e2eabf..fe4b9628d6 100644
--- a/src/frontend/src/App.tsx
+++ b/src/frontend/src/App.tsx
@@ -3,6 +3,7 @@ import "reactflow/dist/style.css";
import "./App.css";
import { ErrorBoundary } from "react-error-boundary";
+import { useNavigate } from "react-router-dom";
import ErrorAlert from "./alerts/error";
import NoticeAlert from "./alerts/notice";
import SuccessAlert from "./alerts/success";
@@ -43,6 +44,9 @@ export default function App() {
const refreshVersion = useDarkStore((state) => state.refreshVersion);
const refreshStars = useDarkStore((state) => state.refreshStars);
const checkHasStore = useStoreStore((state) => state.checkHasStore);
+ const navigate = useNavigate();
+
+ const [isLoadingHealth, setIsLoadingHealth] = useState(false);
useEffect(() => {
refreshStars();
@@ -60,11 +64,12 @@ export default function App() {
}, [isAuthenticated]);
useEffect(() => {
+ checkApplicationHealth();
// Timer to call getHealth every 5 seconds
const timer = setInterval(() => {
getHealth()
.then(() => {
- if (fetchError) setFetchError(false);
+ onHealthCheck();
})
.catch(() => {
setFetchError(true);
@@ -77,6 +82,30 @@ export default function App() {
};
}, []);
+ const checkApplicationHealth = () => {
+ setIsLoadingHealth(true);
+ getHealth()
+ .then(() => {
+ onHealthCheck();
+ })
+ .catch(() => {
+ setFetchError(true);
+ });
+
+ setTimeout(() => {
+ setIsLoadingHealth(false);
+ }, 2000);
+ };
+
+ const onHealthCheck = () => {
+ setFetchError(false);
+ //This condition is necessary to avoid infinite loop on starter page when the application is not healthy
+ if (isLoading === true && window.location.pathname === "/") {
+ navigate("/flows");
+ window.location.reload();
+ }
+ };
+
return (
//need parent component with width and height