From 60694258f26893a71c70fff0381154b68878089e Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Thu, 17 Apr 2025 16:19:22 -0400 Subject: [PATCH 01/63] Add backend reachability check method --- src/Utils/NetworkService.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Utils/NetworkService.js b/src/Utils/NetworkService.js index 7c4ffba9f..7ac76f89e 100644 --- a/src/Utils/NetworkService.js +++ b/src/Utils/NetworkService.js @@ -504,6 +504,41 @@ class NetworkService { return this.axiosInstance.get("/auth/users/superadmin"); } + /** + * ************************************ + * Checks if the backend server is reachable + * ************************************ + * + * @async + * @returns {Promise} True if backend is reachable, false otherwise + */ + async checkBackendReachability() { + try { + // Create a temporary instance that doesn't follow redirects and has a short timeout + const tempInstance = axios.create({ + timeout: 5000, + maxRedirects: 0, + baseURL: this.axiosInstance.defaults.baseURL, + }); + + // Make a simple GET request to the root endpoint + await tempInstance.get('/', { + headers: { + Authorization: undefined // Prevent sending the auth token + } + }); + + return true; + } catch (error) { + // If we get a successful HTTP status or redirect, the backend is reachable + if (error.response) { + return true; // Server responded with any status code, so it's reachable + } + console.error("Backend connection failed:", error); + return false; + } + } + /** * ************************************ * Get all users From b404ff3022d5203e13d34f2e2a85802e8d318f8f Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Thu, 17 Apr 2025 16:36:53 -0400 Subject: [PATCH 02/63] some modification --- src/Utils/NetworkService.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Utils/NetworkService.js b/src/Utils/NetworkService.js index 7ac76f89e..583b65089 100644 --- a/src/Utils/NetworkService.js +++ b/src/Utils/NetworkService.js @@ -516,7 +516,6 @@ class NetworkService { try { // Create a temporary instance that doesn't follow redirects and has a short timeout const tempInstance = axios.create({ - timeout: 5000, maxRedirects: 0, baseURL: this.axiosInstance.defaults.baseURL, }); From 402361ce97bb71621192f599acd81041c2600aa6 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Mon, 21 Apr 2025 10:57:49 -0400 Subject: [PATCH 03/63] error message in login page and translation --- client/src/Pages/Auth/Login/Login.jsx | 118 ++++++++++++++++++++++---- client/src/locales/gb.json | 8 ++ client/src/locales/ru.json | 8 ++ client/src/locales/tr.json | 8 ++ 4 files changed, 127 insertions(+), 15 deletions(-) diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index 9db56ae49..52663a479 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Stack, Typography, Alert, Button } from "@mui/material"; import { useTheme } from "@emotion/react"; import { credentials } from "../../../Validation/validation"; import { login } from "../../../Features/Auth/authSlice"; @@ -16,6 +16,7 @@ import PasswordStep from "./Components/PasswordStep"; import ThemeSwitch from "../../../Components/ThemeSwitch"; import ForgotPasswordLabel from "./Components/ForgotPasswordLabel"; import LanguageSelector from "../../../Components/LanguageSelector"; +import { useTranslation } from "react-i18next"; const DEMO = import.meta.env.VITE_APP_DEMO; @@ -27,6 +28,7 @@ const Login = () => { const dispatch = useDispatch(); const navigate = useNavigate(); const theme = useTheme(); + const { t } = useTranslation(); const authState = useSelector((state) => state.auth); const { authToken } = authState; @@ -42,22 +44,81 @@ const Login = () => { }); const [errors, setErrors] = useState({}); const [step, setStep] = useState(0); + const [backendReachable, setBackendReachable] = useState(true); + const [isCheckingConnection, setIsCheckingConnection] = useState(false); useEffect(() => { if (authToken) { navigate("/uptime"); return; } - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); + + // Check backend connectivity first + const handleRetry = async () => { + setIsCheckingConnection(true); + try { + const isReachable = await networkService.checkBackendReachability(); + setBackendReachable(isReachable); + + // If backend is now reachable, proceed with admin check + if (isReachable) { + networkService + .doesSuperAdminExist() + .then((response) => { + if (response.data.data === false) { + navigate("/register"); + } + }) + .catch((error) => { + logger.error(error); + }); + createToast({ + body: t("backendReconnected"), + }); + } else { + createToast({ + body: t("backendStillUnreachable"), + }); } - }) - .catch((error) => { - logger.error(error); - }); + } catch (error) { + logger.error("Error checking backend connectivity:", error); + setBackendReachable(false); + createToast({ + body: t("backendConnectionError"), + }); + } finally { + setIsCheckingConnection(false); + } + }; + + const checkConnectivity = async () => { + setIsCheckingConnection(true); + try { + const isReachable = await networkService.checkBackendReachability(); + setBackendReachable(isReachable); + + // Only proceed with admin check if backend is reachable + if (isReachable) { + networkService + .doesSuperAdminExist() + .then((response) => { + if (response.data.data === false) { + navigate("/register"); + } + }) + .catch((error) => { + logger.error(error); + }); + } + } catch (error) { + logger.error("Error checking backend connectivity:", error); + setBackendReachable(false); + } finally { + setIsCheckingConnection(false); + } + }; + + checkConnectivity(); }, [authToken, navigate]); const handleChange = (event) => { @@ -82,6 +143,14 @@ const Login = () => { const handleSubmit = async (event) => { event.preventDefault(); + // Check backend connectivity before proceeding + if (!backendReachable) { + createToast({ + body: t("backendUnreachableError"), + }); + return; + } + if (step === 0) { const { error } = credentials.validate( { email: form.email }, @@ -208,7 +277,24 @@ const Login = () => { }, }} > - {step === 0 ? ( + {!backendReachable ? ( + + + {t("backendUnreachable")} + + + {t("backendUnreachableMessage")} + + + + ) : step === 0 ? ( { /> ) )} - + {backendReachable && ( + + )} ); diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index 343386bec..3bfb07fcf 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -99,6 +99,14 @@ "settingsFailedToAddDemoMonitors": "Failed to add demo monitors", "settingsMonitorsDeleted": "Successfully deleted all monitors", "settingsFailedToDeleteMonitors": "Failed to delete all monitors", + "backendUnreachable": "Server Connection Error", + "backendUnreachableMessage": "We're unable to connect to the server. Please check your internet connection or contact your administrator if the problem persists.", + "backendUnreachableError": "Cannot connect to the server. Please try again later.", + "retryConnection": "Retry Connection", + "retryingConnection": "Connecting...", + "backendReconnected": "Successfully reconnected to the server.", + "backendStillUnreachable": "Server is still unreachable. Please try again later.", + "backendConnectionError": "Error connecting to the server. Please check your network connection.", "starPromptTitle": "Star Checkmate", "starPromptDescription": "See the latest releases and help grow the community on GitHub", "https": "HTTPS", diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index 5d0f649de..4845830ef 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -99,6 +99,14 @@ "settingsFailedToAddDemoMonitors": "Не удалось добавить демонстрационные мониторы", "settingsMonitorsDeleted": "Успешно удалены все мониторы", "settingsFailedToDeleteMonitors": "Не удалось удалить все мониторы", + "backendUnreachable": "Ошибка подключения к серверу", + "backendUnreachableMessage": "Мы не можем подключиться к серверу. Пожалуйста, проверьте ваше интернет-соединение или обратитесь к администратору, если проблема не устраняется.", + "backendUnreachableError": "Невозможно подключиться к серверу. Пожалуйста, повторите попытку позже.", + "retryConnection": "Повторить подключение", + "retryingConnection": "Подключение...", + "backendReconnected": "Успешно восстановлено подключение к серверу.", + "backendStillUnreachable": "Сервер по-прежнему недоступен. Пожалуйста, повторите попытку позже.", + "backendConnectionError": "Ошибка подключения к серверу. Пожалуйста, проверьте ваше сетевое подключение.", "starPromptTitle": "Star Checkmate", "starPromptDescription": "Ознакомьтесь с последними релизами и помогите развить сообщество на GitHub", "https": "HTTPS", diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index 1b759a29d..11d79fabc 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -99,6 +99,14 @@ "settingsFailedToAddDemoMonitors": "Demo monitörler eklenemedi", "settingsMonitorsDeleted": "Tüm monitörler başarıyla silindi", "settingsFailedToDeleteMonitors": "Monitörler silinemedi", + "backendUnreachable": "Sunucu Bağlantı Hatası", + "backendUnreachableMessage": "Sunucuya bağlanamıyoruz. Lütfen internet bağlantınızı kontrol edin veya sorun devam ederse yöneticinize başvurun.", + "backendUnreachableError": "Sunucuya bağlanılamıyor. Lütfen daha sonra tekrar deneyin.", + "retryConnection": "Bağlantıyı Yeniden Dene", + "retryingConnection": "Bağlanıyor...", + "backendReconnected": "Sunucuya başarıyla yeniden bağlandı.", + "backendStillUnreachable": "Sunucu hala erişilemez durumda. Lütfen daha sonra tekrar deneyin.", + "backendConnectionError": "Sunucuya bağlanırken hata oluştu. Lütfen ağ bağlantınızı kontrol edin.", "starPromptTitle": "Checkmate yıldızla değerlendirin", "starPromptDescription": "En son sürümleri görün ve GitHub'daki topluluğun büyümesine yardımcı olun", "https": "HTTPS", From b4f2c2c1c2d6bfd6c5ef6e989560d8c69c2cb676 Mon Sep 17 00:00:00 2001 From: Mohadeseh Safari <139602878+mohicody@users.noreply.github.com> Date: Mon, 21 Apr 2025 11:05:42 -0400 Subject: [PATCH 04/63] Delete client/src/Pages/Auth/Login/Login.jsx --- client/src/Pages/Auth/Login/Login.jsx | 326 -------------------------- 1 file changed, 326 deletions(-) delete mode 100644 client/src/Pages/Auth/Login/Login.jsx diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx deleted file mode 100644 index 52663a479..000000000 --- a/client/src/Pages/Auth/Login/Login.jsx +++ /dev/null @@ -1,326 +0,0 @@ -import { useState, useEffect } from "react"; -import { useNavigate } from "react-router-dom"; -import { Box, Stack, Typography, Alert, Button } from "@mui/material"; -import { useTheme } from "@emotion/react"; -import { credentials } from "../../../Validation/validation"; -import { login } from "../../../Features/Auth/authSlice"; -import { useDispatch, useSelector } from "react-redux"; -import { createToast } from "../../../Utils/toastUtils"; -import { networkService } from "../../../main"; -import Background from "../../../assets/Images/background-grid.svg?react"; -import Logo from "../../../assets/icons/checkmate-icon.svg?react"; -import { logger } from "../../../Utils/Logger"; -import "../index.css"; -import EmailStep from "./Components/EmailStep"; -import PasswordStep from "./Components/PasswordStep"; -import ThemeSwitch from "../../../Components/ThemeSwitch"; -import ForgotPasswordLabel from "./Components/ForgotPasswordLabel"; -import LanguageSelector from "../../../Components/LanguageSelector"; -import { useTranslation } from "react-i18next"; - -const DEMO = import.meta.env.VITE_APP_DEMO; - -/** - * Displays the login page. - */ - -const Login = () => { - const dispatch = useDispatch(); - const navigate = useNavigate(); - const theme = useTheme(); - const { t } = useTranslation(); - - const authState = useSelector((state) => state.auth); - const { authToken } = authState; - - const idMap = { - "login-email-input": "email", - "login-password-input": "password", - }; - - const [form, setForm] = useState({ - email: DEMO !== undefined ? "uptimedemo@demo.com" : "", - password: DEMO !== undefined ? "Demouser1!" : "", - }); - const [errors, setErrors] = useState({}); - const [step, setStep] = useState(0); - const [backendReachable, setBackendReachable] = useState(true); - const [isCheckingConnection, setIsCheckingConnection] = useState(false); - - useEffect(() => { - if (authToken) { - navigate("/uptime"); - return; - } - - // Check backend connectivity first - const handleRetry = async () => { - setIsCheckingConnection(true); - try { - const isReachable = await networkService.checkBackendReachability(); - setBackendReachable(isReachable); - - // If backend is now reachable, proceed with admin check - if (isReachable) { - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); - createToast({ - body: t("backendReconnected"), - }); - } else { - createToast({ - body: t("backendStillUnreachable"), - }); - } - } catch (error) { - logger.error("Error checking backend connectivity:", error); - setBackendReachable(false); - createToast({ - body: t("backendConnectionError"), - }); - } finally { - setIsCheckingConnection(false); - } - }; - - const checkConnectivity = async () => { - setIsCheckingConnection(true); - try { - const isReachable = await networkService.checkBackendReachability(); - setBackendReachable(isReachable); - - // Only proceed with admin check if backend is reachable - if (isReachable) { - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); - } - } catch (error) { - logger.error("Error checking backend connectivity:", error); - setBackendReachable(false); - } finally { - setIsCheckingConnection(false); - } - }; - - checkConnectivity(); - }, [authToken, navigate]); - - const handleChange = (event) => { - const { value, id } = event.target; - const name = idMap[id]; - const lowerCasedValue = name === idMap["login-email-input"]? value?.toLowerCase()||value : value - setForm((prev) => ({ - ...prev, - [name]: lowerCasedValue, - })); - - const { error } = credentials.validate({ [name]: lowerCasedValue }, { abortEarly: false }); - - setErrors((prev) => { - const prevErrors = { ...prev }; - if (error) prevErrors[name] = error.details[0].message; - else delete prevErrors[name]; - return prevErrors; - }); - }; - - const handleSubmit = async (event) => { - event.preventDefault(); - - // Check backend connectivity before proceeding - if (!backendReachable) { - createToast({ - body: t("backendUnreachableError"), - }); - return; - } - - if (step === 0) { - const { error } = credentials.validate( - { email: form.email }, - { abortEarly: false } - ); - if (error) { - setErrors((prev) => ({ ...prev, email: error.details[0].message })); - createToast({ body: error.details[0].message }); - } else { - setStep(1); - } - } else if (step === 1) { - const { error } = credentials.validate(form, { abortEarly: false }); - - if (error) { - // validation errors - const newErrors = {}; - error.details.forEach((err) => { - newErrors[err.path[0]] = err.message; - }); - setErrors(newErrors); - createToast({ - body: - error.details && error.details.length > 0 - ? error.details[0].message - : "Error validating data.", - }); - } else { - const action = await dispatch(login(form)); - if (action.payload.success) { - navigate("/uptime"); - createToast({ - body: "Welcome back! You're successfully logged in.", - }); - } else { - if (action.payload) { - if (action.payload.msg === "Incorrect password") - setErrors({ - password: "The password you provided does not match our records", - }); - // dispatch errors - createToast({ - body: action.payload.msg, - }); - } else { - // unknown errors - createToast({ - body: "Unknown error.", - }); - } - } - } - } - }; - - return ( - - - - - - - - Checkmate - - - - - - - .MuiStack-root": { - border: 1, - borderRadius: theme.spacing(5), - borderColor: theme.palette.primary.lowContrast, - backgroundColor: theme.palette.primary.main, - padding: { - xs: theme.spacing(12), - sm: theme.spacing(20), - }, - }, - }} - > - {!backendReachable ? ( - - - {t("backendUnreachable")} - - - {t("backendUnreachableMessage")} - - - - ) : step === 0 ? ( - - ) : ( - step === 1 && ( - setStep(0)} - /> - ) - )} - {backendReachable && ( - - )} - - - ); -}; - -export default Login; From 0508fde86cf70dd4188cf0371744c47f829d00d8 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Mon, 21 Apr 2025 13:57:26 -0400 Subject: [PATCH 05/63] modify login page --- client/src/Pages/Auth/Login/Login.jsx | 144 +++++++++++++------------- 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index 52663a479..7eaf4d441 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import { useNavigate } from "react-router-dom"; import { Box, Stack, Typography, Alert, Button } from "@mui/material"; import { useTheme } from "@emotion/react"; @@ -44,82 +44,69 @@ const Login = () => { }); const [errors, setErrors] = useState({}); const [step, setStep] = useState(0); + + // State variables for backend connectivity status and loading state const [backendReachable, setBackendReachable] = useState(true); const [isCheckingConnection, setIsCheckingConnection] = useState(false); + // Function to check if the backend server is reachable and handle connectivity status + // Wrapped in useCallback to prevent recreation on each render + const checkConnectivity = useCallback(async (isRetry = false) => { + setIsCheckingConnection(true); + try { + const isReachable = await networkService.checkBackendReachability(); + setBackendReachable(isReachable); + + if (isReachable) { + networkService + .doesSuperAdminExist() + .then((response) => { + if (response.data.data === false) { + navigate("/register"); + } + }) + .catch((error) => { + logger.error(error); + }); + + // Only show reconnection toast if this was a retry attempt + if (isRetry) { + createToast({ + body: t("backendReconnected"), + }); + } + } else if (isRetry) { + // Only show still unreachable toast if this was a retry attempt + createToast({ + body: t("backendStillUnreachable"), + }); + } + } catch (error) { + logger.error("Error checking backend connectivity:", error); + setBackendReachable(false); + + if (isRetry) { + createToast({ + body: t("backendConnectionError"), + }); + } + } finally { + setIsCheckingConnection(false); + } + }, [navigate, t]); + + // Function to handle retry button click + const handleRetry = () => checkConnectivity(true); + useEffect(() => { if (authToken) { navigate("/uptime"); return; } - - // Check backend connectivity first - const handleRetry = async () => { - setIsCheckingConnection(true); - try { - const isReachable = await networkService.checkBackendReachability(); - setBackendReachable(isReachable); - - // If backend is now reachable, proceed with admin check - if (isReachable) { - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); - createToast({ - body: t("backendReconnected"), - }); - } else { - createToast({ - body: t("backendStillUnreachable"), - }); - } - } catch (error) { - logger.error("Error checking backend connectivity:", error); - setBackendReachable(false); - createToast({ - body: t("backendConnectionError"), - }); - } finally { - setIsCheckingConnection(false); - } - }; - - const checkConnectivity = async () => { - setIsCheckingConnection(true); - try { - const isReachable = await networkService.checkBackendReachability(); - setBackendReachable(isReachable); - - // Only proceed with admin check if backend is reachable - if (isReachable) { - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); - } - } catch (error) { - logger.error("Error checking backend connectivity:", error); - setBackendReachable(false); - } finally { - setIsCheckingConnection(false); - } - }; - + + // Initial connectivity check checkConnectivity(); - }, [authToken, navigate]); + }, [authToken, navigate, checkConnectivity]); const handleChange = (event) => { const { value, id } = event.target; @@ -142,7 +129,7 @@ const Login = () => { const handleSubmit = async (event) => { event.preventDefault(); - + // Check backend connectivity before proceeding if (!backendReachable) { createToast({ @@ -279,7 +266,21 @@ const Login = () => { > {!backendReachable ? ( - + {t("backendUnreachable")} @@ -287,9 +288,10 @@ const Login = () => { From c0adbb5bd7625bcac807a23813b725599e4309a6 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Mon, 21 Apr 2025 16:06:44 -0400 Subject: [PATCH 06/63] modify login --- client/src/Pages/Auth/Login/Login.jsx | 30 +++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index 7eaf4d441..0440d14b6 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -58,16 +58,24 @@ const Login = () => { setBackendReachable(isReachable); if (isReachable) { - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); + // Only check if super admin exists if not already attempting to log in + // This allows users to log in even if system thinks no super admin exists + if (window.location.pathname === "/" || window.location.pathname === "") { + networkService + .doesSuperAdminExist() + .then((response) => { + if (response.data.data === false) { + // Add a toast notification instead of forcing redirect + createToast({ + body: t("noSuperAdminMessage"), + type: "info" + }); + } + }) + .catch((error) => { + logger.error(error); + }); + } // Only show reconnection toast if this was a retry attempt if (isRetry) { @@ -93,7 +101,7 @@ const Login = () => { } finally { setIsCheckingConnection(false); } - }, [navigate, t]); + }, [t]); // Removed navigate since we no longer use it within this function // Function to handle retry button click const handleRetry = () => checkConnectivity(true); From 4b92683c7268dc67534c31740ed2d4dd3f6fdcce Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Mon, 21 Apr 2025 22:00:28 -0400 Subject: [PATCH 07/63] some modification --- client/src/Pages/Auth/Login/Login.jsx | 49 ++++++++++++++++++++++----- client/src/locales/gb.json | 4 ++- client/src/locales/ru.json | 2 ++ client/src/locales/tr.json | 2 ++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index 0440d14b6..a5eec8898 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -48,6 +48,7 @@ const Login = () => { // State variables for backend connectivity status and loading state const [backendReachable, setBackendReachable] = useState(true); const [isCheckingConnection, setIsCheckingConnection] = useState(false); + const [initialCheckComplete, setInitialCheckComplete] = useState(false); // Function to check if the backend server is reachable and handle connectivity status // Wrapped in useCallback to prevent recreation on each render @@ -100,6 +101,7 @@ const Login = () => { } } finally { setIsCheckingConnection(false); + setInitialCheckComplete(true); } }, [t]); // Removed navigate since we no longer use it within this function @@ -272,8 +274,13 @@ const Login = () => { }, }} > - {!backendReachable ? ( - + {!initialCheckComplete ? ( + + {/* Show loading state while doing initial connectivity check */} + {t("retryingConnection")} + + ) : !backendReachable ? ( + { > {t("backendUnreachable")} - + {t("backendUnreachableMessage")} @@ -323,10 +334,32 @@ const Login = () => { ) )} {backendReachable && ( - + <> + + + {/* Registration link */} + + + {t("doNotHaveAccount")} + + navigate("/register")} + > + {t("registerHere")} + + + )} diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index 3bfb07fcf..e24362dc8 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -1,5 +1,7 @@ { "dontHaveAccount": "Don't have account", + "doNotHaveAccount": "Do not have an account?", + "registerHere": "Register here", "email": "E-mail", "forgotPassword": "Forgot Password", "password": "password", @@ -102,7 +104,7 @@ "backendUnreachable": "Server Connection Error", "backendUnreachableMessage": "We're unable to connect to the server. Please check your internet connection or contact your administrator if the problem persists.", "backendUnreachableError": "Cannot connect to the server. Please try again later.", - "retryConnection": "Retry Connection", + "retryConnection": "Retry connection", "retryingConnection": "Connecting...", "backendReconnected": "Successfully reconnected to the server.", "backendStillUnreachable": "Server is still unreachable. Please try again later.", diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index 4845830ef..33a7c615c 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -1,5 +1,7 @@ { "dontHaveAccount": "Нет аккаунта", + "doNotHaveAccount": "У вас нет учетной записи?", + "registerHere": "Зарегистрироваться здесь", "email": "Почта", "forgotPassword": "Забыли пароль", "password": "пароль", diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index 11d79fabc..767384b9d 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -1,5 +1,7 @@ { "dontHaveAccount": "Hesabınız yok mu", + "doNotHaveAccount": "Hesabınız yok mu?", + "registerHere": "Buradan kayıt olun", "email": "E-posta", "forgotPassword": "Parolamı unuttum", "password": "Parola", From eec11f303c6aeb8657f719a1fa2302db6ccab0d3 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Wed, 23 Apr 2025 23:28:35 -0400 Subject: [PATCH 08/63] applied the feedback --- .../Pages/Auth/Login/Components/EmailStep.jsx | 9 ++ .../Auth/Login/Components/PasswordStep.jsx | 19 +++- client/src/Pages/Auth/Login/Login.jsx | 87 +++++++++++-------- 3 files changed, 80 insertions(+), 35 deletions(-) diff --git a/client/src/Pages/Auth/Login/Components/EmailStep.jsx b/client/src/Pages/Auth/Login/Components/EmailStep.jsx index ec5a4b2db..d50212e85 100644 --- a/client/src/Pages/Auth/Login/Components/EmailStep.jsx +++ b/client/src/Pages/Auth/Login/Components/EmailStep.jsx @@ -70,8 +70,17 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => { color="accent" type="submit" disabled={errors.email && true} + className="dashboard-style-button" sx={{ width: "30%", + px: theme.spacing(6), + borderRadius: `${theme.shape.borderRadius}px !important`, + '&.MuiButtonBase-root': { + borderRadius: `${theme.shape.borderRadius}px !important` + }, + '&.MuiButton-root': { + borderRadius: `${theme.shape.borderRadius}px !important` + }, "&.Mui-focusVisible": { outline: `2px solid ${theme.palette.primary.main}`, outlineOffset: `2px`, diff --git a/client/src/Pages/Auth/Login/Components/PasswordStep.jsx b/client/src/Pages/Auth/Login/Components/PasswordStep.jsx index 0b8142161..a57246e23 100644 --- a/client/src/Pages/Auth/Login/Components/PasswordStep.jsx +++ b/client/src/Pages/Auth/Login/Components/PasswordStep.jsx @@ -75,8 +75,16 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => { variant="outlined" color="info" onClick={onBack} + className="dashboard-style-button" sx={{ px: theme.spacing(5), + borderRadius: `${theme.shape.borderRadius}px !important`, + '&.MuiButtonBase-root': { + borderRadius: `${theme.shape.borderRadius}px !important` + }, + '&.MuiButton-root': { + borderRadius: `${theme.shape.borderRadius}px !important` + }, "& svg.MuiSvgIcon-root": { mr: theme.spacing(3), }, @@ -95,13 +103,22 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => { type="submit" loading={authState.isLoading} disabled={errors.password && true} + className="dashboard-style-button" sx={{ width: "30%", + px: theme.spacing(4), + borderRadius: `${theme.shape.borderRadius}px !important`, + '&.MuiButtonBase-root': { + borderRadius: `${theme.shape.borderRadius}px !important` + }, + '&.MuiButton-root': { + borderRadius: `${theme.shape.borderRadius}px !important` + }, "&.Mui-focusVisible": { outline: `2px solid ${theme.palette.primary.main}`, outlineOffset: `2px`, - boxShadow: `none`, }, + boxShadow: `none`, }} > {t("continue")} diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index a5eec8898..bbf14be8b 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -1,6 +1,7 @@ import { useState, useEffect, useCallback } from "react"; import { useNavigate } from "react-router-dom"; -import { Box, Stack, Typography, Alert, Button } from "@mui/material"; +import { Box, Stack, Typography, Button } from "@mui/material"; +import Alert from "../../../Components/Alert"; import { useTheme } from "@emotion/react"; import { credentials } from "../../../Validation/validation"; import { login } from "../../../Features/Auth/authSlice"; @@ -281,39 +282,52 @@ const Login = () => { ) : !backendReachable ? ( - - {t("backendUnreachable")} - - - {t("backendUnreachableMessage")} - - + gap: theme.spacing(3) + } + }}> + + + + + {t("backendUnreachableMessage")} + + + + + ) : step === 0 ? ( { component="span" color={theme.palette.accent.main} ml={theme.spacing(2)} - sx={{ userSelect: "none" }} + sx={{ + cursor: 'pointer', + '&:hover': { + color: theme.palette.accent.darker + } + }} onClick={() => navigate("/register")} > {t("registerHere")} From 720f60cbb7ff894711625adcf5fb8c6f3fcf10cd Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Sun, 27 Apr 2025 12:57:38 -0400 Subject: [PATCH 09/63] Improve backend connectivity check with early returns and Remove unrelated super admin check to focus on backend reachability --- client/src/Pages/Auth/Login/Login.jsx | 35 ++++++++------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index bbf14be8b..0e5c5dcaf 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -59,36 +59,21 @@ const Login = () => { const isReachable = await networkService.checkBackendReachability(); setBackendReachable(isReachable); - if (isReachable) { - // Only check if super admin exists if not already attempting to log in - // This allows users to log in even if system thinks no super admin exists - if (window.location.pathname === "/" || window.location.pathname === "") { - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - // Add a toast notification instead of forcing redirect - createToast({ - body: t("noSuperAdminMessage"), - type: "info" - }); - } - }) - .catch((error) => { - logger.error(error); - }); - } - - // Only show reconnection toast if this was a retry attempt + // Early return if backend is not reachable + if (isReachable === false) { + // Show toast only on retry attempts if (isRetry) { createToast({ - body: t("backendReconnected"), + body: t("backendStillUnreachable"), }); } - } else if (isRetry) { - // Only show still unreachable toast if this was a retry attempt + return; + } + + // Show reconnection toast if this was a retry attempt and backend is now reachable + if (isRetry) { createToast({ - body: t("backendStillUnreachable"), + body: t("backendReconnected"), }); } } catch (error) { From ce6789791e4540e0ddff71f144f7b73d099f7bd9 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Thu, 1 May 2025 14:17:22 -0400 Subject: [PATCH 10/63] changed error message --- client/src/locales/gb.json | 2 +- client/src/locales/ru.json | 2 +- client/src/locales/tr.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index e24362dc8..aaecdef98 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -102,7 +102,7 @@ "settingsMonitorsDeleted": "Successfully deleted all monitors", "settingsFailedToDeleteMonitors": "Failed to delete all monitors", "backendUnreachable": "Server Connection Error", - "backendUnreachableMessage": "We're unable to connect to the server. Please check your internet connection or contact your administrator if the problem persists.", + "backendUnreachableMessage": "We're unable to connect to the server. Please check your internet connection or verify your deployment configuration if the problem persists.", "backendUnreachableError": "Cannot connect to the server. Please try again later.", "retryConnection": "Retry connection", "retryingConnection": "Connecting...", diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index 33a7c615c..5b2d6aa0c 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -102,7 +102,7 @@ "settingsMonitorsDeleted": "Успешно удалены все мониторы", "settingsFailedToDeleteMonitors": "Не удалось удалить все мониторы", "backendUnreachable": "Ошибка подключения к серверу", - "backendUnreachableMessage": "Мы не можем подключиться к серверу. Пожалуйста, проверьте ваше интернет-соединение или обратитесь к администратору, если проблема не устраняется.", + "backendUnreachableMessage": "Мы не можем подключиться к серверу. Пожалуйста, проверьте ваше интернет-соединение или проверьте конфигурацию развертывания, если проблема не устраняется.", "backendUnreachableError": "Невозможно подключиться к серверу. Пожалуйста, повторите попытку позже.", "retryConnection": "Повторить подключение", "retryingConnection": "Подключение...", diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index 767384b9d..e2c7b3827 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -102,7 +102,7 @@ "settingsMonitorsDeleted": "Tüm monitörler başarıyla silindi", "settingsFailedToDeleteMonitors": "Monitörler silinemedi", "backendUnreachable": "Sunucu Bağlantı Hatası", - "backendUnreachableMessage": "Sunucuya bağlanamıyoruz. Lütfen internet bağlantınızı kontrol edin veya sorun devam ederse yöneticinize başvurun.", + "backendUnreachableMessage": "Sunucuya bağlanamıyoruz. Lütfen internet bağlantınızı kontrol edin veya sorun devam ederse dağıtım yapılandırmanızı doğrulayın.", "backendUnreachableError": "Sunucuya bağlanılamıyor. Lütfen daha sonra tekrar deneyin.", "retryConnection": "Bağlantıyı Yeniden Dene", "retryingConnection": "Bağlanıyor...", From 3df19fc51691d71ebfae3d1df9605a9650baa48f Mon Sep 17 00:00:00 2001 From: Pezhman Parsaee Date: Sun, 4 May 2025 01:21:53 +0200 Subject: [PATCH 11/63] hide certificate expiry box for non-http uptimes --- .../Components/UptimeStatusBoxes/index.jsx | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx index 66c021aa2..ddc7e223b 100644 --- a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx +++ b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx @@ -61,18 +61,20 @@ const UptimeStatusBoxes = ({ } /> - - {certificateExpiry} - - } - /> + {monitor?.type === "http" && ( + + {certificateExpiry} + + } + /> + )} ); }; From fd64a673608a22e3c9577fcab4a2b193437c4ee5 Mon Sep 17 00:00:00 2001 From: Pezhman Parsaee Date: Sun, 4 May 2025 11:34:36 +0200 Subject: [PATCH 12/63] defined a constant for the type of monitors --- .../Uptime/Details/Components/UptimeStatusBoxes/index.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx index ddc7e223b..80e1d2072 100644 --- a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx +++ b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx @@ -7,6 +7,13 @@ import { useTheme } from "@mui/material/styles"; import { Typography } from "@mui/material"; import useUtils from "../../../Monitors/Hooks/useUtils"; +const MONITOR_TYPES = { + WEB: ["http", "https"], + PING: ["ping"], + DOCKER: ["docker"], + PORT: ["port"], +}; + const UptimeStatusBoxes = ({ isLoading = false, monitor, From d68c8e523d80b69af203d4f7c7fc740c2c041858 Mon Sep 17 00:00:00 2001 From: Pezhman Parsaee Date: Sun, 4 May 2025 11:35:48 +0200 Subject: [PATCH 13/63] changed conditional rendering to hide certificate expiry box for non http uptimes --- .../Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx index 80e1d2072..9391256c5 100644 --- a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx +++ b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx @@ -68,7 +68,7 @@ const UptimeStatusBoxes = ({ } /> - {monitor?.type === "http" && ( + {MONITOR_TYPES.WEB.includes(monitor?.type) && ( Date: Sun, 4 May 2025 22:54:55 -0400 Subject: [PATCH 14/63] using axios response interceptor --- client/src/Pages/Auth/Login/Login.jsx | 185 +++++-------------------- client/src/Pages/ServerUnreachable.jsx | 171 +++++++++++++++++++++++ client/src/Routes/index.jsx | 7 + client/src/Utils/NetworkService.js | 9 ++ 4 files changed, 220 insertions(+), 152 deletions(-) create mode 100644 client/src/Pages/ServerUnreachable.jsx diff --git a/client/src/Pages/Auth/Login/Login.jsx b/client/src/Pages/Auth/Login/Login.jsx index 0e5c5dcaf..e43346640 100644 --- a/client/src/Pages/Auth/Login/Login.jsx +++ b/client/src/Pages/Auth/Login/Login.jsx @@ -1,16 +1,13 @@ -import { useState, useEffect, useCallback } from "react"; +import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { Box, Stack, Typography, Button } from "@mui/material"; -import Alert from "../../../Components/Alert"; +import { Box, Stack, Typography } from "@mui/material"; import { useTheme } from "@emotion/react"; import { credentials } from "../../../Validation/validation"; import { login } from "../../../Features/Auth/authSlice"; import { useDispatch, useSelector } from "react-redux"; import { createToast } from "../../../Utils/toastUtils"; -import { networkService } from "../../../main"; import Background from "../../../assets/Images/background-grid.svg?react"; import Logo from "../../../assets/icons/checkmate-icon.svg?react"; -import { logger } from "../../../Utils/Logger"; import "../index.css"; import EmailStep from "./Components/EmailStep"; import PasswordStep from "./Components/PasswordStep"; @@ -46,63 +43,13 @@ const Login = () => { const [errors, setErrors] = useState({}); const [step, setStep] = useState(0); - // State variables for backend connectivity status and loading state - const [backendReachable, setBackendReachable] = useState(true); - const [isCheckingConnection, setIsCheckingConnection] = useState(false); - const [initialCheckComplete, setInitialCheckComplete] = useState(false); - // Function to check if the backend server is reachable and handle connectivity status - // Wrapped in useCallback to prevent recreation on each render - const checkConnectivity = useCallback(async (isRetry = false) => { - setIsCheckingConnection(true); - try { - const isReachable = await networkService.checkBackendReachability(); - setBackendReachable(isReachable); - - // Early return if backend is not reachable - if (isReachable === false) { - // Show toast only on retry attempts - if (isRetry) { - createToast({ - body: t("backendStillUnreachable"), - }); - } - return; - } - - // Show reconnection toast if this was a retry attempt and backend is now reachable - if (isRetry) { - createToast({ - body: t("backendReconnected"), - }); - } - } catch (error) { - logger.error("Error checking backend connectivity:", error); - setBackendReachable(false); - - if (isRetry) { - createToast({ - body: t("backendConnectionError"), - }); - } - } finally { - setIsCheckingConnection(false); - setInitialCheckComplete(true); - } - }, [t]); // Removed navigate since we no longer use it within this function - - // Function to handle retry button click - const handleRetry = () => checkConnectivity(true); useEffect(() => { if (authToken) { navigate("/uptime"); - return; } - - // Initial connectivity check - checkConnectivity(); - }, [authToken, navigate, checkConnectivity]); + }, [authToken, navigate]); const handleChange = (event) => { const { value, id } = event.target; @@ -125,14 +72,6 @@ const Login = () => { const handleSubmit = async (event) => { event.preventDefault(); - - // Check backend connectivity before proceeding - if (!backendReachable) { - createToast({ - body: t("backendUnreachableError"), - }); - return; - } if (step === 0) { const { error } = credentials.validate( @@ -260,61 +199,7 @@ const Login = () => { }, }} > - {!initialCheckComplete ? ( - - {/* Show loading state while doing initial connectivity check */} - {t("retryingConnection")} - - ) : !backendReachable ? ( - - - - - - - {t("backendUnreachableMessage")} - - - - - - - ) : step === 0 ? ( + {step === 0 ? ( { /> ) )} - {backendReachable && ( - <> - - - {/* Registration link */} - - - {t("doNotHaveAccount")} - - navigate("/register")} - > - {t("registerHere")} - - - - )} + + + {/* Registration link */} + + + {t("doNotHaveAccount")} + + navigate("/register")} + > + {t("registerHere")} + + ); diff --git a/client/src/Pages/ServerUnreachable.jsx b/client/src/Pages/ServerUnreachable.jsx new file mode 100644 index 000000000..b635a8460 --- /dev/null +++ b/client/src/Pages/ServerUnreachable.jsx @@ -0,0 +1,171 @@ +import React, { useState } from "react"; +import { Box, Typography, Button, Stack } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import { useNavigate } from "react-router"; +import { networkService } from "../Utils/NetworkService"; +import Alert from "../Components/Alert"; +import { createToast } from "../Utils/toastUtils"; +import { useTranslation } from "react-i18next"; +import Background from "../assets/Images/background-grid.svg?react"; +import Logo from "../assets/icons/checkmate-icon.svg?react"; +import ThemeSwitch from "../Components/ThemeSwitch"; +import LanguageSelector from "../Components/LanguageSelector"; + +const ServerUnreachable = () => { + const theme = useTheme(); + const navigate = useNavigate(); + const { t } = useTranslation(); + + // State for tracking connection check status + const [isCheckingConnection, setIsCheckingConnection] = useState(false); + + const handleRetry = React.useCallback(async () => { + setIsCheckingConnection(true); + try { + // Try to connect to the backend with a simple API call + // We'll use any lightweight endpoint that doesn't require authentication + await networkService.axiosInstance.get('/health', { timeout: 5000 }); + + // If successful, show toast and navigate to login page + createToast({ + body: t("backendReconnected", "Connection to server restored"), + }); + navigate("/login"); + } catch (error) { + // If still unreachable, stay on this page and show toast + console.error("Server still unreachable:", error); + createToast({ + body: t("backendStillUnreachable", "Server is still unreachable"), + }); + } finally { + setIsCheckingConnection(false); + } + }, [navigate, t]); + + return ( + + + + + + {/* Header with logo */} + + + + Checkmate + + + + + + + .MuiStack-root": { + border: 1, + borderRadius: theme.spacing(5), + borderColor: theme.palette.primary.lowContrast, + backgroundColor: theme.palette.primary.main, + padding: { + xs: theme.spacing(12), + sm: theme.spacing(20), + }, + }, + }} + > + + + + + + + {t("backendUnreachableMessage", "The Checkmate server is not responding. Please check your deployment configuration or try again later.")} + + + + + + + + + ); +}; + +export default ServerUnreachable; diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx index 82d7af7ca..90be1282e 100644 --- a/client/src/Routes/index.jsx +++ b/client/src/Routes/index.jsx @@ -36,6 +36,9 @@ import DistributedUptimeDetails from "../Pages/DistributedUptime/Details"; import CreateDistributedUptimeStatus from "../Pages/DistributedUptimeStatus/Create"; import DistributedUptimeStatus from "../Pages/DistributedUptimeStatus/Status"; +// Server Status +import ServerUnreachable from "../Pages/ServerUnreachable"; + // Incidents import Incidents from "../Pages/Incidents"; @@ -279,6 +282,10 @@ const Routes = () => { element={} /> + } + /> } diff --git a/client/src/Utils/NetworkService.js b/client/src/Utils/NetworkService.js index 583b65089..8a06fc9da 100644 --- a/client/src/Utils/NetworkService.js +++ b/client/src/Utils/NetworkService.js @@ -45,6 +45,15 @@ class NetworkService { this.axiosInstance.interceptors.response.use( (response) => response, (error) => { + // Handle network errors (server unreachable) + if (error.code === "ERR_NETWORK") { + // Navigate to server unreachable page + navigate("/server-unreachable"); + // Return an empty resolved promise to stop the error propagation + return Promise.reject(error); + } + + // Handle authentication errors if (error.response && error.response.status === 401) { dispatch(clearAuthState()); dispatch(clearUptimeMonitorState()); From 8e495d12513b9e6a3a6cfb53212f04c3b512bdc1 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Sun, 4 May 2025 23:16:34 -0400 Subject: [PATCH 15/63] remove "the backend server is reachable" --- client/src/Utils/NetworkService.js | 34 +----------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/client/src/Utils/NetworkService.js b/client/src/Utils/NetworkService.js index 8a06fc9da..90f35d7e3 100644 --- a/client/src/Utils/NetworkService.js +++ b/client/src/Utils/NetworkService.js @@ -513,39 +513,7 @@ class NetworkService { return this.axiosInstance.get("/auth/users/superadmin"); } - /** - * ************************************ - * Checks if the backend server is reachable - * ************************************ - * - * @async - * @returns {Promise} True if backend is reachable, false otherwise - */ - async checkBackendReachability() { - try { - // Create a temporary instance that doesn't follow redirects and has a short timeout - const tempInstance = axios.create({ - maxRedirects: 0, - baseURL: this.axiosInstance.defaults.baseURL, - }); - - // Make a simple GET request to the root endpoint - await tempInstance.get('/', { - headers: { - Authorization: undefined // Prevent sending the auth token - } - }); - - return true; - } catch (error) { - // If we get a successful HTTP status or redirect, the backend is reachable - if (error.response) { - return true; // Server responded with any status code, so it's reachable - } - console.error("Backend connection failed:", error); - return false; - } - } + /** * ************************************ From 288fd4ca1b8a0309a887b630f9d187bd3b65609e Mon Sep 17 00:00:00 2001 From: Pezhman Parsaee Date: Mon, 5 May 2025 20:36:43 +0200 Subject: [PATCH 16/63] removed newly created constant for monitor types --- .../Uptime/Details/Components/UptimeStatusBoxes/index.jsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx index 9391256c5..f3ea2dfa6 100644 --- a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx +++ b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx @@ -7,13 +7,6 @@ import { useTheme } from "@mui/material/styles"; import { Typography } from "@mui/material"; import useUtils from "../../../Monitors/Hooks/useUtils"; -const MONITOR_TYPES = { - WEB: ["http", "https"], - PING: ["ping"], - DOCKER: ["docker"], - PORT: ["port"], -}; - const UptimeStatusBoxes = ({ isLoading = false, monitor, From 9b216cd059b8814da70cada808983de4fcc8025e Mon Sep 17 00:00:00 2001 From: Pezhman Parsaee Date: Mon, 5 May 2025 20:38:19 +0200 Subject: [PATCH 17/63] changed the condition to show the certificate expiry box for http monitor type --- .../Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx index f3ea2dfa6..ddc7e223b 100644 --- a/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx +++ b/client/src/Pages/Uptime/Details/Components/UptimeStatusBoxes/index.jsx @@ -61,7 +61,7 @@ const UptimeStatusBoxes = ({ } /> - {MONITOR_TYPES.WEB.includes(monitor?.type) && ( + {monitor?.type === "http" && ( Date: Mon, 5 May 2025 14:56:24 -0400 Subject: [PATCH 18/63] add new inputfield for api key in settings --- client/src/Pages/Settings/index.jsx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 1bad8414d..7e04d6390 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -54,6 +54,7 @@ const Settings = () => { const [form, setForm] = useState({ enableDistributedUptime: distributedUptimeEnabled, ttl: checkTTL ? (checkTTL / SECONDS_PER_DAY).toString() : 0, + pagespeedApiKey: "", }); const [version, setVersion] = useState("unknown"); const [errors, setErrors] = useState({}); @@ -277,6 +278,26 @@ const Settings = () => { )} + + + Google Pagespeed API Key + + Manage your pagespeed API key + + + + + + {isAdmin && ( From 2f8981e379a9c6aab50821d391b3dd64e35dab28 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Mon, 5 May 2025 15:10:32 -0400 Subject: [PATCH 19/63] import and use adorment in textinput to toggle visibility --- client/src/Pages/Settings/index.jsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 7e04d6390..c43ebf69e 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -6,6 +6,7 @@ import Select from "../../Components/Inputs/Select"; import { useIsAdmin } from "../../Hooks/useIsAdmin"; import Dialog from "../../Components/Dialog"; import ConfigBox from "../../Components/ConfigBox"; +import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments"; import { WalletMultiButton, WalletDisconnectButton, @@ -57,6 +58,7 @@ const Settings = () => { pagespeedApiKey: "", }); const [version, setVersion] = useState("unknown"); + const [apiKeyFieldType, setApiKeyFieldType] = useState("password"); const [errors, setErrors] = useState({}); const deleteStatsMonitorsInitState = { deleteMonitors: false, deleteStats: false }; const [isOpen, setIsOpen] = useState(deleteStatsMonitorsInitState); @@ -290,11 +292,17 @@ const Settings = () => { id="pagespeedApiKey" label="PageSpeed API Key" value={form.pagespeedApiKey} + type={apiKeyFieldType} onChange={handleChange} - type="password" optionalLabel="(Optional)" - helperText={errors.pagespeedApiKey} error={!!errors.pagespeedApiKey} + helperText={errors.pagespeedApiKey} + endAdornment={ + + } /> From cc454ab51962007c81e69211a9d2e8e1d3c9f68e Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Mon, 5 May 2025 16:02:59 -0400 Subject: [PATCH 20/63] update loadSettings logic to prioritize db env values for testing --- server/service/settingsService.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/server/service/settingsService.js b/server/service/settingsService.js index 1443755f9..91dd73b38 100755 --- a/server/service/settingsService.js +++ b/server/service/settingsService.js @@ -48,12 +48,9 @@ class SettingsService { // If there are any settings that weren't set by environment variables, use user settings from DB for (const key in envConfig) { - if ( - typeof envConfig?.[key] === "undefined" && - typeof dbSettings?.[key] !== "undefined" - ) { + if (typeof dbSettings?.[key] !== "undefined") { this.settings[key] = dbSettings[key]; - } + } } await this.appSettings.updateOne({}, { $set: this.settings }, { upsert: true }); From d4ed97992fad549c59d34901efb7daff360184ee Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Mon, 5 May 2025 16:03:30 -0400 Subject: [PATCH 21/63] update dispatch action to include pagespeedapi key --- client/src/Pages/Settings/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index c43ebf69e..456e620ff 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -128,7 +128,7 @@ const Settings = () => { const updatedUser = { ...user, checkTTL: form.ttl }; const [userAction, settingsAction] = await Promise.all([ dispatch(update({ localData: updatedUser })), - dispatch(updateAppSettings({ settings: { language: language } })), + dispatch(updateAppSettings({ settings: { language: language, pagespeedApiKey: form.pagespeedApiKey } })), ]); if (userAction.payload.success && settingsAction.payload.success) { From 86c31eaaf6174dfe339b982edf57728f9b3d90c5 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Mon, 5 May 2025 16:06:24 -0400 Subject: [PATCH 22/63] add pagespeed key to settings validation --- client/src/Validation/validation.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 38092c9e6..0e303c27f 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -255,6 +255,7 @@ const settingsValidation = joi.object({ ttl: joi.number().required().messages({ "string.empty": "TTL is required", }), + pagespeedApiKey: joi.string().allow("").optional(), }); const dayjsValidator = (value, helpers) => { From c7daff8f1fb66460df4d57d6c65d9e753da02cd2 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Mon, 5 May 2025 19:57:12 -0400 Subject: [PATCH 23/63] some of them fixed --- client/src/Pages/Auth/Register/Register.jsx | 2 +- client/src/locales/gb.json | 25 +++++++++--------- client/src/locales/ru.json | 16 +++++++++--- client/src/locales/tr.json | 29 +++++++++++---------- 4 files changed, 42 insertions(+), 30 deletions(-) diff --git a/client/src/Pages/Auth/Register/Register.jsx b/client/src/Pages/Auth/Register/Register.jsx index 45c866797..8017f306d 100644 --- a/client/src/Pages/Auth/Register/Register.jsx +++ b/client/src/Pages/Auth/Register/Register.jsx @@ -387,7 +387,7 @@ const Register = ({ isSuperAdmin }) => { }} sx={{ userSelect: "none", color: theme.palette.accent.main }} > - {t("authLoginTitle")} + {t("authRegisterLoginLink")} diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index 9deaa9e48..b78e4116b 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -3,7 +3,7 @@ "email": "E-mail", "forgotPassword": "Forgot Password", "password": "password", - "signUp": "Sign up", + "signUp": "Sign Up", "submit": "Submit", "title": "Title", "continue": "Continue", @@ -17,6 +17,7 @@ "createPassword": "Create your password", "createAPassword": "Create a password", "authRegisterAlreadyHaveAccount": "Already have an account?", + "authRegisterLoginLink": "Log In", "commonAppName": "Checkmate", "authLoginEnterEmail": "Enter your email", "authRegisterTitle": "Create an account", @@ -85,7 +86,7 @@ "settingsRemoveAllMonitors": "Remove all monitors", "settingsRemoveAllMonitorsButton": "Remove all monitors", "settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?", - "settingsRemoveAllMonitorsDialogConfirm": "Yes, clear all monitors", + "settingsRemoveAllMonitorsDialogConfirm": "Yes, remove all monitors", "settingsWallet": "Wallet", "settingsWalletDescription": "Connect your wallet here. This is required for the Distributed Uptime monitor to connect to multiple nodes globally.", "settingsAbout": "About", @@ -105,12 +106,12 @@ "http": "HTTP", "monitor": "monitor", "aboutus": "About Us", - "signUP": "Sign Up", + "now": "Now", "delete": "Delete", "configure": "Configure", "networkError": "Network error", - "responseTime": "Response time:", + "responseTime": "Response time", "ms": "ms", "bar": "Bar", "area": "Area", @@ -386,16 +387,16 @@ "DragandDrop": "drag and drop", "MaxSize": "Maximum Size", "SupportedFormats": "Supported formats", - "FirstName": "First name", - "LastName": "Last name", - "EmailDescriptionText": "This is your current email address — it cannot be changed.", - "YourPhoto": "Your photo", + "FirstName": "Name", + "LastName": "Surname", + "EmailDescriptionText": "Your current email—it cannot be changed.", + "YourPhoto": "Profile photo", "PhotoDescriptionText": "This photo will be displayed in your profile page.", "save": "Save", - "DeleteAccount": "Delete account", - "DeleteDescriptionText": "Note that deleting your account will remove all data from the server. This is permanent and non-recoverable.", - "DeleteAccountWarning": "If you delete your account, you will no longer be able to sign in, and all of your data will be deleted. Deleting your account is permanent and non-recoverable action.", - "DeleteWarningTitle": "Really delete this account?", + "DeleteAccount": "Remove account", + "DeleteDescriptionText": "This will remove the account and all associated data from the server. This isn't reversible.", + "DeleteAccountWarning": "Removing your account means you won't be able to sign in again and all your data will be removed. This isn't reversible.", + "DeleteWarningTitle": "Really remove this account?", "authRegisterFirstName": "Name", "authRegisterLastName": "Surname", "authRegisterEmail": "Email", diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index 520d34826..001e96c56 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -17,6 +17,7 @@ "createPassword": "Создайте свой пароль", "createAPassword": "Создайте пароль", "authRegisterAlreadyHaveAccount": "Уже есть аккаунт?", + "authRegisterLoginLink": "Войти", "commonAppName": "Checkmate", "authLoginEnterEmail": "Введите свой email", "authRegisterTitle": "Создать аккаунт", @@ -89,7 +90,7 @@ "settingsRemoveAllMonitors": "Удалить все демонстрационные мониторы", "settingsRemoveAllMonitorsButton": "Удалить все демонстрационные мониторы", "settingsRemoveAllMonitorsDialogTitle": "Хотите удалить все мониторы?", - "settingsRemoveAllMonitorsDialogConfirm": "Да, очистить все мониторы", + "settingsRemoveAllMonitorsDialogConfirm": "Да, удалить все мониторы", "settingsWallet": "Кошелёк", "settingsWalletDescription": "Подключите свой кошелек здесь. Это необходимо для того, чтобы монитор Distributed Uptime мог подключиться к нескольким узлам по всему миру.", "settingsAbout": "О", @@ -99,6 +100,15 @@ "settingsFailedToSave": "Не удалось сохранить настройки", "settingsStatsCleared": "Статистика успешно очищена", "settingsFailedToClearStats": "Не удалось очистить статистику", + "FirstName": "Имя", + "LastName": "Фамилия", + "YourPhoto": "Фото профиля", + "PhotoDescriptionText": "Это фото будет отображаться на странице вашего профиля.", + "EmailDescriptionText": "Ваш текущий email—его нельзя изменить.", + "DeleteAccount": "Удалить аккаунт", + "DeleteDescriptionText": "Это удалит аккаунт и все связанные данные с сервера. Это необратимо.", + "DeleteAccountWarning": "Удаление аккаунта означает, что вы не сможете снова войти в систему, и все ваши данные будут удалены. Это необратимо.", + "DeleteWarningTitle": "Действительно удалить этот аккаунт?", "settingsDemoMonitorsAdded": "Успешно добавлены демонстрационные мониторы", "settingsFailedToAddDemoMonitors": "Не удалось добавить демонстрационные мониторы", "settingsMonitorsDeleted": "Успешно удалены все мониторы", @@ -109,12 +119,12 @@ "http": "HTTP", "monitor": "монитор", "aboutus": "О Нас", - "signUP": "Зарегистрироваться", + "now": "Сейчас", "delete": "Удалить", "configure": "Настроить", "networkError": "Ошибка сети", - "responseTime": "Время ответа:", + "responseTime": "Время ответа", "ms": "мс", "bar": "Bar", "area": "Area", diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index b9990f733..e2b163986 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -17,6 +17,7 @@ "createPassword": "Parolanızı oluşturun", "createAPassword": "Bir parola oluşturun", "authRegisterAlreadyHaveAccount": "Zaten hesabınız var mı?", + "authRegisterLoginLink": "Giriş Yap", "commonAppName": "Checkmate", "authLoginEnterEmail": "E-posta adresinizi girin", "authRegisterTitle": "Hesap oluştur", @@ -85,7 +86,7 @@ "settingsRemoveAllMonitors": "Tüm monitörleri kaldır", "settingsRemoveAllMonitorsButton": "Tüm monitörleri kaldır", "settingsRemoveAllMonitorsDialogTitle": "Tüm monitörleri kaldırmak istiyor musunuz?", - "settingsRemoveAllMonitorsDialogConfirm": "Evet, tüm monitörleri temizle", + "settingsRemoveAllMonitorsDialogConfirm": "Evet, tüm monitörleri kaldır", "settingsWallet": "Cüzdan", "settingsWalletDescription": "Cüzdanınızı buradan bağlayın. Bu, Dağıtılmış Çalışma Süresi monitörünün küresel olarak birden çok düğüme bağlanması için gereklidir.", "settingsAbout": "Hakkında", @@ -105,12 +106,12 @@ "http": "HTTP", "monitor": "monitör", "aboutus": "Hakkımızda", - "signUP": "Hesap Oluştur", + "now": "Şimdi", "delete": "Sil", "configure": "Yapılandır", "networkError": "Ağ hatası", - "responseTime": "Yanıt süresi:", + "responseTime": "Yanıt süresi", "ms": "ms", "bar": "Çubuk", "area": "Alan", @@ -386,18 +387,18 @@ "DragandDrop": "", "MaxSize": "", "SupportedFormats": "", - "FirstName": "", - "LastName": "", - "EmailDescriptionText": "", - "YourPhoto": "", - "PhotoDescriptionText": "", + "FirstName": "Ad", + "LastName": "Soyad", + "EmailDescriptionText": "Mevcut e-postanız—değiştirilemez.", + "YourPhoto": "Profil fotoğrafı", + "PhotoDescriptionText": "Bu fotoğraf profil sayfanızda görüntülenecektir.", "save": "", - "DeleteAccount": "", - "DeleteDescriptionText": "", - "DeleteAccountWarning": "", - "DeleteWarningTitle": "", - "authRegisterFirstName": "", - "authRegisterLastName": "", + "DeleteAccount": "Hesabı kaldır", + "DeleteDescriptionText": "Bu, hesabı ve tüm ilişkili verileri sunucudan kaldıracaktır. Bu geri alınamaz.", + "DeleteAccountWarning": "Hesabınızı kaldırmak, tekrar oturum açamayacağınız ve tüm verilerinizin kaldırılacağı anlamına gelir. Bu geri alınamaz.", + "DeleteWarningTitle": "Bu hesabı gerçekten kaldırmak istiyor musunuz?", + "authRegisterFirstName": "Ad", + "authRegisterLastName": "Soyad", "authRegisterEmail": "", "authRegisterEmailRequired": "", "bulkImport": { From 3469954ad81f205b59b98946ba85b1afc848092b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 6 May 2025 10:26:31 -0700 Subject: [PATCH 24/63] hotfix/validation --- server/validation/joi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/validation/joi.js b/server/validation/joi.js index fdd51b8d2..bd402fb8a 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -183,7 +183,7 @@ const createMonitorBodyValidation = joi.object({ description: joi.string().required(), type: joi.string().required(), url: joi.string().required(), - ignoreTlsErrors: joi.boolean().required(), + ignoreTlsErrors: joi.boolean().default(false), port: joi.number(), isActive: joi.boolean(), interval: joi.number(), From ddb2b55c4203f6beb65b267477503ee22603501d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 6 May 2025 10:52:17 -0700 Subject: [PATCH 25/63] uncomment notifications for pagespeed --- client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js b/client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js index 11cbcb36c..3ed2da13f 100644 --- a/client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js +++ b/client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js @@ -101,7 +101,7 @@ export const updatePageSpeed = createAsyncThunk( name: monitor.name, description: monitor.description, interval: monitor.interval, - // notifications: monitor.notifications, + notifications: monitor.notifications, }; const res = await networkService.updateMonitor({ monitorId: monitor._id, From 4bc9f59d809c25035c77026f5f8c1e25b328dfea Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 6 May 2025 10:53:07 -0700 Subject: [PATCH 26/63] fix loading prop --- client/src/Pages/PageSpeed/Monitors/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Pages/PageSpeed/Monitors/index.jsx b/client/src/Pages/PageSpeed/Monitors/index.jsx index f10ba73d0..9963e429c 100644 --- a/client/src/Pages/PageSpeed/Monitors/index.jsx +++ b/client/src/Pages/PageSpeed/Monitors/index.jsx @@ -62,7 +62,7 @@ const PageSpeed = () => { Date: Tue, 6 May 2025 11:05:13 -0700 Subject: [PATCH 27/63] provide default empty notification array --- server/controllers/monitorController.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/server/controllers/monitorController.js b/server/controllers/monitorController.js index 6295a9aba..5ab654375 100755 --- a/server/controllers/monitorController.js +++ b/server/controllers/monitorController.js @@ -538,18 +538,16 @@ class MonitorController { const monitorBeforeEdit = await this.db.getMonitorById(monitorId); // Get notifications from the request body - const notifications = req.body.notifications; - + const notifications = req.body.notifications ?? []; const editedMonitor = await this.db.editMonitor(monitorId, req.body); await this.db.deleteNotificationsByMonitorId(editedMonitor._id); await Promise.all( - notifications && - notifications.map(async (notification) => { - notification.monitorId = editedMonitor._id; - await this.db.createNotification(notification); - }) + notifications.map(async (notification) => { + notification.monitorId = editedMonitor._id; + await this.db.createNotification(notification); + }) ); // Delete the old job(editedMonitor has the same ID as the old monitor) From 47f84941937a85737ccc1121a7e86710f2541ce3 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Tue, 6 May 2025 14:29:59 -0400 Subject: [PATCH 28/63] update handlechange to modify form validation logic --- client/src/Pages/Settings/index.jsx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 456e620ff..64607648d 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -94,12 +94,17 @@ const Settings = () => { return; } + let inputValue = value; + if (id === "ttl") { + inputValue = value.replace(/[^0-9]/g, ""); + } + + const updatedForm = { ...form, [id]: inputValue }; const { error } = settingsValidation.validate( - { [id]: value }, - { - abortEarly: false, - } + updatedForm, + { abortEarly: false } ); + if (!error || error.details.length === 0) { setErrors({}); } else { @@ -110,12 +115,8 @@ const Settings = () => { setErrors(newErrors); logger.error("Validation errors:", error.details); } - let inputValue = value; - id === "ttl" && (inputValue = value.replace(/[^0-9]/g, "")); - setForm((prev) => ({ - ...prev, - [id]: inputValue, - })); + + setForm(updatedForm); }; // TODO Handle saving From 336ffcc9e98235a71a6f18c1261f8b691df72516 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Tue, 6 May 2025 14:53:24 -0400 Subject: [PATCH 29/63] Add .unknown(true) to validation schema to ignore extra fields --- client/src/Validation/validation.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 0e303c27f..9c4b12c7a 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -256,7 +256,8 @@ const settingsValidation = joi.object({ "string.empty": "TTL is required", }), pagespeedApiKey: joi.string().allow("").optional(), -}); +}) +.unknown(true); const dayjsValidator = (value, helpers) => { if (!dayjs(value).isValid()) { From 9dc6c3c7b1046915f881f86d6df01f9477aecae1 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Tue, 6 May 2025 14:57:07 -0400 Subject: [PATCH 30/63] revert loadsettings changes --- server/service/settingsService.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/service/settingsService.js b/server/service/settingsService.js index 91dd73b38..1443755f9 100755 --- a/server/service/settingsService.js +++ b/server/service/settingsService.js @@ -48,9 +48,12 @@ class SettingsService { // If there are any settings that weren't set by environment variables, use user settings from DB for (const key in envConfig) { - if (typeof dbSettings?.[key] !== "undefined") { + if ( + typeof envConfig?.[key] === "undefined" && + typeof dbSettings?.[key] !== "undefined" + ) { this.settings[key] = dbSettings[key]; - } + } } await this.appSettings.updateOne({}, { $set: this.settings }, { upsert: true }); From 3e8f3a7a89e72615e06786075e6d1aca2b7ad9c9 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Tue, 6 May 2025 15:56:01 -0400 Subject: [PATCH 31/63] include pagespeedapikey to parsedSettings to save in db --- client/src/Features/Settings/settingsSlice.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/Features/Settings/settingsSlice.js b/client/src/Features/Settings/settingsSlice.js index 614ab7159..51f85a2b5 100644 --- a/client/src/Features/Settings/settingsSlice.js +++ b/client/src/Features/Settings/settingsSlice.js @@ -33,6 +33,7 @@ export const updateAppSettings = createAsyncThunk( try { const parsedSettings = { language: settings.language, + pagespeedApiKey: settings.pagespeedApiKey, }; const res = await networkService.updateAppSettings({ settings: parsedSettings }); return res.data; From b493b5e0e5749b7b8ee528ddefb7991c3db46e73 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Tue, 6 May 2025 15:57:00 -0400 Subject: [PATCH 32/63] modify loadSettings logic to fetch env from DB --- server/service/settingsService.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/server/service/settingsService.js b/server/service/settingsService.js index 1443755f9..7a219a89d 100755 --- a/server/service/settingsService.js +++ b/server/service/settingsService.js @@ -48,11 +48,14 @@ class SettingsService { // If there are any settings that weren't set by environment variables, use user settings from DB for (const key in envConfig) { - if ( - typeof envConfig?.[key] === "undefined" && - typeof dbSettings?.[key] !== "undefined" - ) { - this.settings[key] = dbSettings[key]; + + const envValue = envConfig[key]; + const dbValue = dbSettings?.[key]; + + if (envValue === undefined || envValue === "") { + if (dbValue !== undefined) { + this.settings[key] = dbValue; + } } } From 85c3a16f411e5a94d3662a971f22e0488855f79d Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Tue, 6 May 2025 16:45:48 -0400 Subject: [PATCH 33/63] add pagespeed to intialstate and handler in settingsslice --- client/src/Features/Settings/settingsSlice.js | 2 ++ server/service/settingsService.js | 13 +++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/client/src/Features/Settings/settingsSlice.js b/client/src/Features/Settings/settingsSlice.js index 51f85a2b5..35e17e360 100644 --- a/client/src/Features/Settings/settingsSlice.js +++ b/client/src/Features/Settings/settingsSlice.js @@ -6,6 +6,7 @@ const initialState = { apiBaseUrl: "", logLevel: "debug", language: "", + pagespeedApiKey: "", }; export const getAppSettings = createAsyncThunk( @@ -57,6 +58,7 @@ const handleGetSettingsFulfilled = (state, action) => { state.apiBaseUrl = action.payload.data.apiBaseUrl; state.logLevel = action.payload.data.logLevel; state.language = action.payload.data.language; + state.pagespeedApiKey = action.payload.data.pagespeedApiKey; }; const handleGetSettingsRejected = (state, action) => { state.isLoading = false; diff --git a/server/service/settingsService.js b/server/service/settingsService.js index 7a219a89d..1443755f9 100755 --- a/server/service/settingsService.js +++ b/server/service/settingsService.js @@ -48,14 +48,11 @@ class SettingsService { // If there are any settings that weren't set by environment variables, use user settings from DB for (const key in envConfig) { - - const envValue = envConfig[key]; - const dbValue = dbSettings?.[key]; - - if (envValue === undefined || envValue === "") { - if (dbValue !== undefined) { - this.settings[key] = dbValue; - } + if ( + typeof envConfig?.[key] === "undefined" && + typeof dbSettings?.[key] !== "undefined" + ) { + this.settings[key] = dbSettings[key]; } } From 91d373264511a2b4ab25834c003acfdd0ed9dfa9 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Tue, 6 May 2025 16:47:53 -0400 Subject: [PATCH 34/63] add useffect to load pagespeed key in the form --- client/src/Pages/Settings/index.jsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 64607648d..b82407e05 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -83,6 +83,15 @@ const Settings = () => { fetchLatestVersion(); }, []); + const { pagespeedApiKey } = useSelector((state) => state.settings); + + useEffect(() => { + setForm((prev) => ({ + ...prev, + pagespeedApiKey: pagespeedApiKey || "", + })); + }, [pagespeedApiKey]); + const handleChange = (event) => { const { type, checked, value, id } = event.target; From 8aa609c0ab39c683219c78834e5dcda6963b9bf0 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Tue, 6 May 2025 20:25:19 -0400 Subject: [PATCH 35/63] fix translation --- client/src/Components/TabPanels/Account/ProfilePanel.jsx | 6 +++--- client/src/locales/gb.json | 3 ++- client/src/locales/ru.json | 3 ++- client/src/locales/tr.json | 3 ++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/client/src/Components/TabPanels/Account/ProfilePanel.jsx b/client/src/Components/TabPanels/Account/ProfilePanel.jsx index aa6c11f3c..bdf52de3a 100644 --- a/client/src/Components/TabPanels/Account/ProfilePanel.jsx +++ b/client/src/Components/TabPanels/Account/ProfilePanel.jsx @@ -344,7 +344,7 @@ const ProfilePanel = () => { spellCheck="false" > - {t('DeleteAccount')} + {t('DeleteAccountTitle')} { color="error" onClick={() => setIsOpen("delete")} > - {t('DeleteAccount')} + {t('DeleteAccountButton')} )} @@ -367,7 +367,7 @@ const ProfilePanel = () => { title={t('DeleteWarningTitle')} description={t('DeleteAccountWarning')} onCancel={() => setIsOpen("")} - confirmationButtonLabel={t('DeleteAccount')} + confirmationButtonLabel={t('DeleteAccountButton')} onConfirm={handleDeleteAccount} isLoading={isLoading} /> diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index b78e4116b..ce82f8dff 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -393,7 +393,8 @@ "YourPhoto": "Profile photo", "PhotoDescriptionText": "This photo will be displayed in your profile page.", "save": "Save", - "DeleteAccount": "Remove account", + "DeleteAccountTitle": "Remove account", + "DeleteAccountButton": "Remove account", "DeleteDescriptionText": "This will remove the account and all associated data from the server. This isn't reversible.", "DeleteAccountWarning": "Removing your account means you won't be able to sign in again and all your data will be removed. This isn't reversible.", "DeleteWarningTitle": "Really remove this account?", diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index 001e96c56..e694394b7 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -105,7 +105,8 @@ "YourPhoto": "Фото профиля", "PhotoDescriptionText": "Это фото будет отображаться на странице вашего профиля.", "EmailDescriptionText": "Ваш текущий email—его нельзя изменить.", - "DeleteAccount": "Удалить аккаунт", + "DeleteAccountTitle": "Удалить аккаунт", + "DeleteAccountButton": "Удалить аккаунт", "DeleteDescriptionText": "Это удалит аккаунт и все связанные данные с сервера. Это необратимо.", "DeleteAccountWarning": "Удаление аккаунта означает, что вы не сможете снова войти в систему, и все ваши данные будут удалены. Это необратимо.", "DeleteWarningTitle": "Действительно удалить этот аккаунт?", diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index e2b163986..f4a5c4b01 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -393,7 +393,8 @@ "YourPhoto": "Profil fotoğrafı", "PhotoDescriptionText": "Bu fotoğraf profil sayfanızda görüntülenecektir.", "save": "", - "DeleteAccount": "Hesabı kaldır", + "DeleteAccountTitle": "Hesabı kaldır", + "DeleteAccountButton": "Hesabı kaldır", "DeleteDescriptionText": "Bu, hesabı ve tüm ilişkili verileri sunucudan kaldıracaktır. Bu geri alınamaz.", "DeleteAccountWarning": "Hesabınızı kaldırmak, tekrar oturum açamayacağınız ve tüm verilerinizin kaldırılacağı anlamına gelir. Bu geri alınamaz.", "DeleteWarningTitle": "Bu hesabı gerçekten kaldırmak istiyor musunuz?", From aafdff3b0aad1469faae2e5150607788a34a7e53 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 6 May 2025 18:46:35 -0700 Subject: [PATCH 36/63] add client-host --- docker/dist/docker-compose.yaml | 1 + docker/prod/docker-compose.yaml | 2 +- docker/staging/docker-compose.yaml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/dist/docker-compose.yaml b/docker/dist/docker-compose.yaml index 230623c8d..ca8e24061 100755 --- a/docker/dist/docker-compose.yaml +++ b/docker/dist/docker-compose.yaml @@ -4,6 +4,7 @@ services: restart: always environment: UPTIME_APP_API_BASE_URL: "http://localhost:5000/api/v1" + UPTIME_APP_CLIENT_HOST: "http://localhost" ports: - "80:80" - "443:443" diff --git a/docker/prod/docker-compose.yaml b/docker/prod/docker-compose.yaml index 770aaad9c..bc720862f 100755 --- a/docker/prod/docker-compose.yaml +++ b/docker/prod/docker-compose.yaml @@ -4,7 +4,7 @@ services: restart: always environment: UPTIME_APP_API_BASE_URL: "https://checkmate-demo.bluewavelabs.ca/api/v1" - UPTIME_STATUS_PAGE_SUBDOMAIN_PREFIX: "http://uptimegenie.com/" + UPTIME_APP_CLIENT_HOST: "https://checkmate-demo.bluewavelabs.ca" ports: - "80:80" - "443:443" diff --git a/docker/staging/docker-compose.yaml b/docker/staging/docker-compose.yaml index 8117dc01b..d491a729e 100755 --- a/docker/staging/docker-compose.yaml +++ b/docker/staging/docker-compose.yaml @@ -4,7 +4,7 @@ services: restart: always environment: UPTIME_APP_API_BASE_URL: "https://checkmate-test.bluewavelabs.ca/api/v1" - UPTIME_STATUS_PAGE_SUBDOMAIN_PREFIX: "http://uptimegenie.com/" + UPTIME_APP_CLIENT_HOST: "https://checkmate-test.bluewavelabs.ca" ports: - "80:80" - "443:443" From 038b7a150c0d70cc137163badd972ccae19e94f0 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 6 May 2025 19:01:23 -0700 Subject: [PATCH 37/63] fix env var name --- client/src/Hooks/inviteHooks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Hooks/inviteHooks.js b/client/src/Hooks/inviteHooks.js index f8b44f0fd..705906efa 100644 --- a/client/src/Hooks/inviteHooks.js +++ b/client/src/Hooks/inviteHooks.js @@ -2,7 +2,7 @@ import { useState } from "react"; import { networkService } from "../main"; import { useTranslation } from "react-i18next"; -const CLIENT_HOST = import.meta.env.VITE_CLIENT_HOST; +const CLIENT_HOST = import.meta.env.VITE_APP_CLIENT_HOST; const useGetInviteToken = () => { const { t } = useTranslation(); From 74b1d3e245303b209746f16f457ae88b9b1858bd Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Tue, 6 May 2025 22:08:36 -0400 Subject: [PATCH 38/63] Low quality of English text --- .../TabPanels/Account/PasswordPanel.jsx | 4 ++- .../Pages/Auth/Login/Components/EmailStep.jsx | 2 +- client/src/Pages/Auth/Login/Login.jsx | 16 ++++++---- client/src/locales/gb.json | 30 +++++++++++-------- client/src/locales/ru.json | 30 +++++++++++-------- client/src/locales/tr.json | 28 +++++++++-------- 6 files changed, 65 insertions(+), 45 deletions(-) diff --git a/client/src/Components/TabPanels/Account/PasswordPanel.jsx b/client/src/Components/TabPanels/Account/PasswordPanel.jsx index 6f2775cf1..474058e66 100644 --- a/client/src/Components/TabPanels/Account/PasswordPanel.jsx +++ b/client/src/Components/TabPanels/Account/PasswordPanel.jsx @@ -10,6 +10,7 @@ import { update } from "../../../Features/Auth/authSlice"; import { useDispatch, useSelector } from "react-redux"; import { createToast } from "../../../Utils/toastUtils"; import { getTouchedFieldErrors } from "../../../Validation/error"; +import { useTranslation } from "react-i18next"; const defaultPasswordsState = { password: "", @@ -26,6 +27,7 @@ const defaultPasswordsState = { const PasswordPanel = () => { const theme = useTheme(); const dispatch = useDispatch(); + const { t } = useTranslation(); const SPACING_GAP = theme.spacing(12); @@ -203,7 +205,7 @@ const PasswordPanel = () => { { onInput={(e) => (e.target.value = e.target.value.toLowerCase())} onChange={onChange} error={errors.email ? true : false} - helperText={errors.email} + helperText={errors.email ? t(errors.email) : ""} ref={inputRef} /> { - const dispatch = useDispatch(); - const navigate = useNavigate(); const theme = useTheme(); + const dispatch = useDispatch(); + const { t } = useTranslation(); + const navigate = useNavigate(); const authState = useSelector((state) => state.auth); const { authToken } = authState; @@ -88,8 +90,10 @@ const Login = () => { { abortEarly: false } ); if (error) { - setErrors((prev) => ({ ...prev, email: error.details[0].message })); - createToast({ body: error.details[0].message }); + const errorMessage = error.details[0].message; + const translatedMessage = errorMessage.startsWith('auth') ? t(errorMessage) : errorMessage; + setErrors((prev) => ({ ...prev, email: translatedMessage })); + createToast({ body: translatedMessage }); } else { setStep(1); } @@ -106,8 +110,8 @@ const Login = () => { createToast({ body: error.details && error.details.length > 0 - ? error.details[0].message - : "Error validating data.", + ? (error.details[0].message.startsWith('auth') ? t(error.details[0].message) : error.details[0].message) + : t("Error validating data."), }); } else { const action = await dispatch(login(form)); diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index ce82f8dff..3f6e82cbc 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -2,7 +2,7 @@ "dontHaveAccount": "Don't have account", "email": "E-mail", "forgotPassword": "Forgot Password", - "password": "password", + "password": "Password", "signUp": "Sign Up", "submit": "Submit", "title": "Title", @@ -15,7 +15,7 @@ "authForgotPasswordTitle": "Forgot password?", "authForgotPasswordResetPassword": "Reset password", "createPassword": "Create your password", - "createAPassword": "Create a password", + "createAPassword": "Password", "authRegisterAlreadyHaveAccount": "Already have an account?", "authRegisterLoginLink": "Log In", "commonAppName": "Checkmate", @@ -41,7 +41,7 @@ "authSetNewPasswordDescription": "Your new password must be different from previously used passwords.", "authSetNewPasswordNewPassword": "New password", "authSetNewPasswordConfirmPassword": "Confirm password", - "confirmPassword": "Confirm your password", + "confirmPassword": "Re-enter password to confirm", "authSetNewPasswordResetPassword": "Reset password", "authSetNewPasswordBackTo": "Back to", "authPasswordMustBeAtLeast": "Must be at least", @@ -52,7 +52,10 @@ "authPasswordUpperCharacter": "one upper character", "authPasswordLowerCharacter": "one lower character", "authPasswordConfirmAndPassword": "Confirm password and password", - "authPasswordMustMatch": "must match", + "authPasswordMustMatch": "Passwords must match", + "validationNameRequired": "Please enter your name", + "validationNameTooLong": "Name should be less than 50 characters", + "validationNameInvalidCharacters": "Please use only letters, spaces, apostrophes, or hyphens", "authRegisterCreateAccount": "Create your account to get started", "authRegisterCreateSuperAdminAccount": "Create your super admin account to get started", "authRegisterSignUpWithEmail": "Create super admin account", @@ -61,7 +64,7 @@ "distributedStatusSubHeaderText": "Powered by millions devices worldwide, view a system performance by global region, country or city", "settingsGeneralSettings": "General settings", "settingsDisplayTimezone": "Display timezone", - "settingsDisplayTimezoneDescription": "The timezone of the dashboard you publicly display.", + "settingsDisplayTimezoneDescription": "Select the timezone used to display dates and times throughout the application.", "settingsAppearance": "Appearance", "settingsAppearanceDescription": "Switch between light and dark mode, or change user interface language", "settingsThemeMode": "Theme Mode", @@ -70,20 +73,22 @@ "settingsDistributedUptimeDescription": "Enable/disable distributed uptime monitoring.", "settingsEnabled": "Enabled", "settingsDisabled": "Disabled", - "settingsHistoryAndMonitoring": "History and monitoring", - "settingsHistoryAndMonitoringDescription": "Define here for how long you want to keep the data. You can also remove all past data.", + "settingsHistoryAndMonitoring": "History of monitoring", + "settingsHistoryAndMonitoringDescription": "Define how long you want to retain historical data. You can also clear all existing data.", "settingsTTLLabel": "The days you want to keep monitoring history.", "settingsTTLOptionalLabel": "0 for infinite", "settingsClearAllStats": "Clear all stats. This is irreversible.", "settingsClearAllStatsButton": "Clear all stats", "settingsClearAllStatsDialogTitle": "Do you want to clear all stats?", - "settingsClearAllStatsDialogDescription": "Once deleted, your monitors cannot be retrieved.", + "settingsClearAllStatsDialogDescription": "Once removed, the monitoring history and stats cannot be retrieved.", "settingsClearAllStatsDialogConfirm": "Yes, clear all stats", "settingsDemoMonitors": "Demo monitors", - "settingsDemoMonitorsDescription": "Here you can add and remove demo monitors.", - "settingsAddDemoMonitors": "Add demo monitors", + "settingsDemoMonitorsDescription": "Add sample monitors for demonstration purposes.", + "settingsAddDemoMonitors": "Adding demo monitors", "settingsAddDemoMonitorsButton": "Add demo monitors", - "settingsRemoveAllMonitors": "Remove all monitors", + "settingsSystemReset": "System reset", + "settingsSystemResetDescription": "Remove all monitors from your system.", + "settingsRemoveAllMonitors": "Removing all monitors", "settingsRemoveAllMonitorsButton": "Remove all monitors", "settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?", "settingsRemoveAllMonitorsDialogConfirm": "Yes, remove all monitors", @@ -401,7 +406,8 @@ "authRegisterFirstName": "Name", "authRegisterLastName": "Surname", "authRegisterEmail": "Email", - "authRegisterEmailRequired": "Email is required", + "authRegisterEmailRequired": "To continue, please enter your email address", + "authRegisterEmailInvalid": "Please enter a valid email address", "bulkImport": { "title": "Bulk Import", "selectFileTips": "Select CSV file to upload", diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index e694394b7..ac098629b 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -2,7 +2,7 @@ "dontHaveAccount": "Нет аккаунта", "email": "Почта", "forgotPassword": "Забыли пароль", - "password": "пароль", + "password": "Пароль", "signUp": "Зарегистрироваться", "submit": "Подтвердить", "title": "Название", @@ -15,7 +15,7 @@ "authForgotPasswordTitle": "Забыли пароль?", "authForgotPasswordResetPassword": "Сбросить пароль", "createPassword": "Создайте свой пароль", - "createAPassword": "Создайте пароль", + "createAPassword": "Пароль", "authRegisterAlreadyHaveAccount": "Уже есть аккаунт?", "authRegisterLoginLink": "Войти", "commonAppName": "Checkmate", @@ -41,7 +41,8 @@ "authSetNewPasswordDescription": "Ваш новый пароль должен отличаться от ранее использованных паролей.", "authSetNewPasswordNewPassword": "Новый пароль", "authSetNewPasswordConfirmPassword": "Подтвердите пароль", - "confirmPassword": "Подтвердите ваш пароль", + "confirmPassword": "Введите пароль еще раз для подтверждения", + "confirmNewPasswordPlaceholder": "Подтвердите ваш новый пароль", "authSetNewPasswordResetPassword": "Сбросить пароль", "authSetNewPasswordBackTo": "Назад к", "authPasswordMustBeAtLeast": "Должно быть как минимум", @@ -52,7 +53,7 @@ "authPasswordUpperCharacter": "один верхний символ", "authPasswordLowerCharacter": "один нижний символ", "authPasswordConfirmAndPassword": "Подтвердите пароль и пароль", - "authPasswordMustMatch": "должен совпадать", + "authPasswordMustMatch": "Пароли должны совпадать", "authRegisterCreateAccount": "Создайте свою учетную запись, чтобы начать", "authRegisterCreateSuperAdminAccount": "Создайте учетную запись суперадминистратора, чтобы начать работу", "authRegisterSignUpWithEmail": "Создать учетную запись суперадминистратора", @@ -60,12 +61,13 @@ "authRegisterFirstName": "Имя", "authRegisterLastName": "Фамилия", "authRegisterEmail": "Эл. почта", - "authRegisterEmailRequired": "Эл. почта обязательна", + "authRegisterEmailRequired": "Чтобы продолжить, пожалуйста, введите ваш адрес электронной почты", + "authRegisterEmailInvalid": "Пожалуйста, введите корректный адрес электронной почты", "distributedStatusHeaderText": "Охват реального времени и реального устройства", "distributedStatusSubHeaderText": "Работает на миллионах устройств по всему миру, просматривайте производительность системы по глобальному региону, стране или городу", "settingsGeneralSettings": "Общие настройки", "settingsDisplayTimezone": "Отображать часовой пояс", - "settingsDisplayTimezoneDescription": "Часовой пояс панели мониторинга, которую вы публично отображаете.", + "settingsDisplayTimezoneDescription": "Выберите часовой пояс, используемый для отображения дат и времени в приложении.", "settingsAppearance": "Внешний вид", "settingsAppearanceDescription": "Переключение между светлым и темным режимом или изменение языка пользовательского интерфейса", "settingsThemeMode": "Тема", @@ -74,21 +76,23 @@ "settingsDistributedUptimeDescription": "Включить/выключить distributed uptime monitoring.", "settingsEnabled": "Включено", "settingsDisabled": "Выключено", - "settingsHistoryAndMonitoring": "История и мониторинг", - "settingsHistoryAndMonitoringDescription": "Определите здесь, как долго вы хотите хранить данные. Вы также можете удалить все прошлые данные.", + "settingsHistoryAndMonitoring": "История мониторинга", + "settingsHistoryAndMonitoringDescription": "Определите, как долго вы хотите хранить исторические данные. Вы также можете очистить все существующие данные.", "settingsTTLLabel": "Дни, за которыми вы хотите следить.", "settingsTTLOptionalLabel": "0 для бесконечности", "settingsClearAllStats": "Очистить всю статистику. Это необратимо.", "settingsClearAllStatsButton": "Очистить всю статистику", "settingsClearAllStatsDialogTitle": "Хотите очистить всю статистику?", - "settingsClearAllStatsDialogDescription": "После удаления ваши мониторы не могут быть восстановлены.", + "settingsClearAllStatsDialogDescription": "После удаления история мониторинга и статистика не могут быть восстановлены.", "settingsClearAllStatsDialogConfirm": "Да, очистить всю статистику", "settingsDemoMonitors": "Демо мониторы", - "settingsDemoMonitorsDescription": "Здесь вы можете добавлять и удалять демонстрационные мониторы.", - "settingsAddDemoMonitors": "Добавьте демонстрационные мониторы", + "settingsDemoMonitorsDescription": "Добавьте примеры мониторов для демонстрации.", + "settingsAddDemoMonitors": "Добавление демонстрационных мониторов", "settingsAddDemoMonitorsButton": "Добавьте демонстрационные мониторы", - "settingsRemoveAllMonitors": "Удалить все демонстрационные мониторы", - "settingsRemoveAllMonitorsButton": "Удалить все демонстрационные мониторы", + "settingsSystemReset": "Сброс системы", + "settingsSystemResetDescription": "Удалить все мониторы из вашей системы.", + "settingsRemoveAllMonitors": "Удаление всех мониторов", + "settingsRemoveAllMonitorsButton": "Удалить все мониторы", "settingsRemoveAllMonitorsDialogTitle": "Хотите удалить все мониторы?", "settingsRemoveAllMonitorsDialogConfirm": "Да, удалить все мониторы", "settingsWallet": "Кошелёк", diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index f4a5c4b01..fe902cbd8 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -15,7 +15,7 @@ "authForgotPasswordTitle": "Parolanızı mı unuttunuz?", "authForgotPasswordResetPassword": "Parola sıfırla", "createPassword": "Parolanızı oluşturun", - "createAPassword": "Bir parola oluşturun", + "createAPassword": "Parola", "authRegisterAlreadyHaveAccount": "Zaten hesabınız var mı?", "authRegisterLoginLink": "Giriş Yap", "commonAppName": "Checkmate", @@ -41,7 +41,8 @@ "authSetNewPasswordDescription": "Yeni şifreniz daha önce kullanılan şifrelerden farklı olmalıdır.", "authSetNewPasswordNewPassword": "Yeni şifre", "authSetNewPasswordConfirmPassword": "Parolayı onayla", - "confirmPassword": "Parolanızı onaylayın", + "confirmPassword": "Onaylamak için parolayı tekrar girin", + "confirmNewPasswordPlaceholder": "Yeni parolanızı onaylayın", "authSetNewPasswordResetPassword": "Parola sıfırla", "authSetNewPasswordBackTo": "Geri dön", "authPasswordMustBeAtLeast": "En az", @@ -52,7 +53,7 @@ "authPasswordUpperCharacter": "bir büyük harf", "authPasswordLowerCharacter": "bir küçük harf", "authPasswordConfirmAndPassword": "Onay şifresi ve şifre", - "authPasswordMustMatch": "eşleşmelidir", + "authPasswordMustMatch": "Parolalar eşleşmelidir", "authRegisterCreateAccount": "Hesap oluşturmak için devam et", "authRegisterCreateSuperAdminAccount": "Super admin hesabınızı oluşturmak için devam edin", "authRegisterSignUpWithEmail": "E-posta ile kayıt ol", @@ -61,7 +62,7 @@ "distributedStatusSubHeaderText": "Dünya çapında milyonlarca cihaz tarafından desteklenen sistem performansını küresel bölgeye, ülkeye veya şehre göre görüntüleyin", "settingsGeneralSettings": "Genel ayarlar", "settingsDisplayTimezone": "Görüntüleme saat dilimi", - "settingsDisplayTimezoneDescription": "Herkese açık olarak görüntülediğiniz kontrol panelinin saat dilimi.", + "settingsDisplayTimezoneDescription": "Uygulama genelinde tarih ve saatlerin görüntülenmesi için kullanılacak saat dilimini seçin.", "settingsAppearance": "Görünüm", "settingsAppearanceDescription": "Açık ve koyu mod arasında geçiş yapın veya kullanıcı arayüzü dilini değiştirin", "settingsThemeMode": "Tema", @@ -70,20 +71,22 @@ "settingsDistributedUptimeDescription": "Dağıtılmış çalışma süresi izlemeyi etkinleştirin/devre dışı bırakın.", "settingsEnabled": "Etkin", "settingsDisabled": "Devre dışı", - "settingsHistoryAndMonitoring": "Geçmiş ve izleme", - "settingsHistoryAndMonitoringDescription": "Verileri ne kadar süreyle saklamak istediğinizi burada tanımlayın. Ayrıca tüm geçmiş verileri kaldırabilirsiniz.", + "settingsHistoryAndMonitoring": "İzleme geçmişi", + "settingsHistoryAndMonitoringDescription": "Geçmiş verileri ne kadar süre saklamak istediğinizi tanımlayın. Ayrıca mevcut tüm verileri temizleyebilirsiniz.", "settingsTTLLabel": "İzleme geçmişini saklamak istediğiniz gün sayısı.", "settingsTTLOptionalLabel": "Sınırsız için 0", "settingsClearAllStats": "Tüm istatistikleri temizle. Bu geri alınamaz.", "settingsClearAllStatsButton": "Tüm istatistikleri temizle", "settingsClearAllStatsDialogTitle": "Tüm istatistikleri temizlemek istiyor musunuz?", - "settingsClearAllStatsDialogDescription": "Silindikten sonra, monitörleriniz geri alınamaz.", + "settingsClearAllStatsDialogDescription": "Kaldırıldıktan sonra, izleme geçmişi ve istatistikleri geri alınamaz.", "settingsClearAllStatsDialogConfirm": "Evet, tüm istatistikleri temizle", "settingsDemoMonitors": "Demo monitörler", - "settingsDemoMonitorsDescription": "Burada demo monitörler ekleyebilir ve kaldırabilirsiniz.", - "settingsAddDemoMonitors": "Demo monitörler ekle", + "settingsDemoMonitorsDescription": "Gösterim amaçlı örnek monitörler ekleyin.", + "settingsAddDemoMonitors": "Demo monitörler ekleniyor", "settingsAddDemoMonitorsButton": "Demo monitörler ekle", - "settingsRemoveAllMonitors": "Tüm monitörleri kaldır", + "settingsSystemReset": "Sistem sıfırlama", + "settingsSystemResetDescription": "Sisteminizden tüm monitörleri kaldırın.", + "settingsRemoveAllMonitors": "Tüm monitörler kaldırılıyor", "settingsRemoveAllMonitorsButton": "Tüm monitörleri kaldır", "settingsRemoveAllMonitorsDialogTitle": "Tüm monitörleri kaldırmak istiyor musunuz?", "settingsRemoveAllMonitorsDialogConfirm": "Evet, tüm monitörleri kaldır", @@ -400,8 +403,9 @@ "DeleteWarningTitle": "Bu hesabı gerçekten kaldırmak istiyor musunuz?", "authRegisterFirstName": "Ad", "authRegisterLastName": "Soyad", - "authRegisterEmail": "", - "authRegisterEmailRequired": "", + "authRegisterEmail": "E-posta", + "authRegisterEmailRequired": "Devam etmek için lütfen e-posta adresinizi girin", + "authRegisterEmailInvalid": "Lütfen geçerli bir e-posta adresi girin", "bulkImport": { "title": "", "selectFileTips": "", From 9a5de71158f68be93976a6954df548d21e1f7981 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Tue, 6 May 2025 22:15:27 -0400 Subject: [PATCH 39/63] Fix --- .../src/Pages/Auth/Register/StepTwo/index.jsx | 2 +- client/src/Pages/Settings/index.jsx | 49 ++++++++++++------- client/src/Validation/validation.js | 12 +++-- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/client/src/Pages/Auth/Register/StepTwo/index.jsx b/client/src/Pages/Auth/Register/StepTwo/index.jsx index d40ff161f..fbd7e70c1 100644 --- a/client/src/Pages/Auth/Register/StepTwo/index.jsx +++ b/client/src/Pages/Auth/Register/StepTwo/index.jsx @@ -68,7 +68,7 @@ function StepTwo({ form, errors, onSubmit, onChange, onBack }) { onInput={(e) => (e.target.value = e.target.value.toLowerCase())} onChange={onChange} error={errors.email ? true : false} - helperText={errors.email && t("authRegisterEmailRequired")} + helperText={errors.email && (errors.email === "Email is required" ? t("authRegisterEmailRequired") : errors.email === "Must be a valid email address" ? t("authRegisterEmailInvalid") : errors.email)} ref={inputRef} /> { )} {isAdmin && ( - - - {t("settingsDemoMonitors")} - - {t("settingsDemoMonitorsDescription")} - - - + <> + {/* Demo Monitors Section */} + + + {t("settingsDemoMonitors")} + + {t("settingsDemoMonitorsDescription")} + + {t("settingsAddDemoMonitors")} + + + {/* System Reset Section */} + + + {t("settingsSystemReset")} + + {t("settingsSystemResetDescription")} + + {t("settingsRemoveAllMonitors")} - - setIsOpen(deleteStatsMonitorsInitState)} - confirmationButtonLabel={t("settingsRemoveAllMonitorsDialogConfirm")} - onConfirm={handleDeleteAllMonitors} - isLoading={isLoading || authIsLoading || checksIsLoading} - /> - + setIsOpen(deleteStatsMonitorsInitState)} + confirmationButtonLabel={t("settingsRemoveAllMonitorsDialogConfirm")} + onConfirm={handleDeleteAllMonitors} + isLoading={isLoading || authIsLoading || checksIsLoading} + /> + + )} diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 38092c9e6..23e14b84b 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -10,8 +10,8 @@ const nameSchema = joi .pattern(/^[\p{L}\p{M}''\- ]+$/u) .messages({ "string.empty": "Name is required", - "string.max": "Name must be less than 50 characters", - "string.pattern.base": "Name must contain only letters, spaces, apostrophes, or hyphens" + "string.max": "Name should be less than 50 characters", + "string.pattern.base": "Please use only letters, spaces, apostrophes, or hyphens" }); const passwordSchema = joi @@ -66,8 +66,8 @@ const credentials = joi.object({ return lowercasedValue; }) .messages({ - "string.empty": "Email is required", - "string.email": "Must be a valid email address", + "string.empty": "authRegisterEmailRequired", + "string.email": "authRegisterEmailInvalid", }), password: passwordSchema, newPassword: passwordSchema, @@ -253,7 +253,9 @@ const statusPageValidation = joi.object({ }); const settingsValidation = joi.object({ ttl: joi.number().required().messages({ - "string.empty": "TTL is required", + "string.empty": "Please enter a value", + "number.base": "Please enter a valid number", + "any.required": "Please enter a value" }), }); From f928322ec7ecac35a829b888d6d52fcb82106f61 Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Tue, 6 May 2025 22:19:50 -0400 Subject: [PATCH 40/63] . --- client/src/Validation/validation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 23e14b84b..01a2fd48c 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -10,8 +10,8 @@ const nameSchema = joi .pattern(/^[\p{L}\p{M}''\- ]+$/u) .messages({ "string.empty": "Name is required", - "string.max": "Name should be less than 50 characters", - "string.pattern.base": "Please use only letters, spaces, apostrophes, or hyphens" + "string.max": "Name must be less than 50 characters", + "string.pattern.base": "Name must contain only letters, spaces, apostrophes, or hyphens" }); const passwordSchema = joi From 4df4dc72e16f4ddc0ebd31068b84d52d0a05c09e Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Tue, 6 May 2025 22:37:35 -0400 Subject: [PATCH 41/63] improve email validation error handling with partial string matching --- client/src/Pages/Auth/Register/StepTwo/index.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/Pages/Auth/Register/StepTwo/index.jsx b/client/src/Pages/Auth/Register/StepTwo/index.jsx index fbd7e70c1..5f563b303 100644 --- a/client/src/Pages/Auth/Register/StepTwo/index.jsx +++ b/client/src/Pages/Auth/Register/StepTwo/index.jsx @@ -68,7 +68,11 @@ function StepTwo({ form, errors, onSubmit, onChange, onBack }) { onInput={(e) => (e.target.value = e.target.value.toLowerCase())} onChange={onChange} error={errors.email ? true : false} - helperText={errors.email && (errors.email === "Email is required" ? t("authRegisterEmailRequired") : errors.email === "Must be a valid email address" ? t("authRegisterEmailInvalid") : errors.email)} + helperText={errors.email && ( + errors.email.includes("required") ? t("authRegisterEmailRequired") : + errors.email.includes("valid email") ? t("authRegisterEmailInvalid") : + errors.email + )} ref={inputRef} /> Date: Tue, 6 May 2025 23:27:10 -0400 Subject: [PATCH 42/63] simplify styling in ServerUnreachable component --- client/src/Pages/ServerUnreachable.jsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/client/src/Pages/ServerUnreachable.jsx b/client/src/Pages/ServerUnreachable.jsx index b635a8460..aaa61cbc4 100644 --- a/client/src/Pages/ServerUnreachable.jsx +++ b/client/src/Pages/ServerUnreachable.jsx @@ -33,7 +33,6 @@ const ServerUnreachable = () => { navigate("/login"); } catch (error) { // If still unreachable, stay on this page and show toast - console.error("Server still unreachable:", error); createToast({ body: t("backendStillUnreachable", "Server is still unreachable"), }); @@ -46,15 +45,6 @@ const ServerUnreachable = () => { Date: Wed, 7 May 2025 11:31:37 +0530 Subject: [PATCH 43/63] Fix: Status Page Create Monitor Button Loading --- client/src/Pages/StatusPage/StatusPages/index.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/Pages/StatusPage/StatusPages/index.jsx b/client/src/Pages/StatusPage/StatusPages/index.jsx index 6654be38c..095023d76 100644 --- a/client/src/Pages/StatusPage/StatusPages/index.jsx +++ b/client/src/Pages/StatusPage/StatusPages/index.jsx @@ -61,6 +61,7 @@ const StatusPages = () => { label="Create status page" isAdmin={isAdmin} path="/status/uptime/create" + isLoading={isLoading} /> From 6033d1545ef63f146285babe6db86b1bb02b8c82 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 7 May 2025 10:21:41 -0700 Subject: [PATCH 44/63] update .env.produciton, update dev docker build --- docker/dev/build_images.sh | 2 +- docker/dev/client.Dockerfile | 11 +++++---- docker/dev/docker-compose.yaml | 19 +++++++++++---- docker/dev/nginx/conf.d/default.conf | 35 ++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100755 docker/dev/nginx/conf.d/default.conf diff --git a/docker/dev/build_images.sh b/docker/dev/build_images.sh index 4baf442b8..e94be9fa5 100755 --- a/docker/dev/build_images.sh +++ b/docker/dev/build_images.sh @@ -5,7 +5,7 @@ cd "$(dirname "$0")" cd ../.. # Define service names and their corresponding Dockerfiles in parallel arrays -services=("uptime_client" "uptime_database_mongo" "uptime_redis" "uptime_server") +services=("uptime_client" "uptime_mongo" "uptime_redis" "uptime_server") dockerfiles=( "./docker/dev/client.Dockerfile" "./docker/dev/mongoDB.Dockerfile" diff --git a/docker/dev/client.Dockerfile b/docker/dev/client.Dockerfile index fd60f47a2..aa4d228fc 100755 --- a/docker/dev/client.Dockerfile +++ b/docker/dev/client.Dockerfile @@ -18,10 +18,13 @@ COPY ./client/package*.json ./ RUN npm install -COPY ./client . +COPY ./client ./ -RUN npm run build-dev +RUN npm run build -RUN npm install -g serve +FROM nginx:1.27.1-alpine -CMD ["serve","-s", "dist", "-l", "5173"] +COPY --from=build /app/dist /usr/share/nginx/html +COPY --from=build /app/env.sh /docker-entrypoint.d/env.sh +RUN chmod +x /docker-entrypoint.d/env.sh +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker/dev/docker-compose.yaml b/docker/dev/docker-compose.yaml index f8b2c6936..73904da37 100755 --- a/docker/dev/docker-compose.yaml +++ b/docker/dev/docker-compose.yaml @@ -3,8 +3,12 @@ services: image: uptime_client:latest restart: always ports: - - "5173:5173" - + - "80:80" + environment: + UPTIME_APP_API_BASE_URL: "http://localhost:5000/api/v1" + UPTIME_APP_CLIENT_HOST: "http://localhost" + volumes: + - ./nginx/conf.d:/etc/nginx/conf.d/ depends_on: - server server: @@ -31,10 +35,17 @@ services: retries: 5 start_period: 5s mongodb: - image: uptime_database_mongo:latest + image: uptime_mongo:latest restart: always - command: ["mongod", "--quiet"] + command: ["mongod", "--quiet", "--replSet", "rs0", "--bind_ip_all"] ports: - "27017:27017" volumes: - ./mongo/data:/data/db + healthcheck: + test: echo "try { rs.status() } catch (err) { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongodb:27017'}]}) }" | mongosh --port 27017 --quiet + interval: 5s + timeout: 30s + start_period: 0s + start_interval: 1s + retries: 30 diff --git a/docker/dev/nginx/conf.d/default.conf b/docker/dev/nginx/conf.d/default.conf new file mode 100755 index 000000000..9a7690aa5 --- /dev/null +++ b/docker/dev/nginx/conf.d/default.conf @@ -0,0 +1,35 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + + server_name localhost; # Set server name to localhost + server_tokens off; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + # location /api/ { + # proxy_pass http://server:5000/api/; + # proxy_http_version 1.1; + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $scheme; + # proxy_set_header Connection ''; + # chunked_transfer_encoding off; + # proxy_buffering off; + # proxy_cache off; + # } + + location /api-docs/ { + proxy_pass http://server:5000/api-docs/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} \ No newline at end of file From f5954a600ba441181aa797a769312dff2cadc7e0 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 7 May 2025 10:50:55 -0700 Subject: [PATCH 45/63] fix .env.production --- client/.env.production | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/.env.production b/client/.env.production index 2ae6d13cd..7a11848c0 100644 --- a/client/.env.production +++ b/client/.env.production @@ -1,2 +1,3 @@ VITE_APP_API_BASE_URL=UPTIME_APP_API_BASE_URL -VITE_STATUS_PAGE_SUBDOMAIN_PREFIX=UPTIME_STATUS_PAGE_SUBDOMAIN_PREFIX +VITE_APP_CLIENT_HOST=UPTIME_APP_CLIENT_HOST +VITE_APP_LOG_LEVEL=UPTIME_APP_LOG_LEVEL \ No newline at end of file From 26e9ff3568a31aef466774abe64f98cd1864a74a Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 13:51:34 -0400 Subject: [PATCH 46/63] add flag to track if api key is set --- client/src/Pages/Settings/index.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index b82407e05..9c6b0f94f 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -7,6 +7,7 @@ import { useIsAdmin } from "../../Hooks/useIsAdmin"; import Dialog from "../../Components/Dialog"; import ConfigBox from "../../Components/ConfigBox"; import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments"; +import { getAppSettings } from "../../Features/Settings/settingsSlice"; import { WalletMultiButton, WalletDisconnectButton, @@ -59,6 +60,7 @@ const Settings = () => { }); const [version, setVersion] = useState("unknown"); const [apiKeyFieldType, setApiKeyFieldType] = useState("password"); + const [isApiKeySet, setIsApiKeySet] = useState(false); const [errors, setErrors] = useState({}); const deleteStatsMonitorsInitState = { deleteMonitors: false, deleteStats: false }; const [isOpen, setIsOpen] = useState(deleteStatsMonitorsInitState); @@ -83,6 +85,10 @@ const Settings = () => { fetchLatestVersion(); }, []); + useEffect(() => { + dispatch(getAppSettings()); + }, []); + const { pagespeedApiKey } = useSelector((state) => state.settings); useEffect(() => { From 8ce7477b069a8c63942548eae9c67ae6a0a55383 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 13:52:48 -0400 Subject: [PATCH 47/63] update useffect to handle pagespeed key --- client/src/Pages/Settings/index.jsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 9c6b0f94f..77ce770bd 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -92,11 +92,20 @@ const Settings = () => { const { pagespeedApiKey } = useSelector((state) => state.settings); useEffect(() => { - setForm((prev) => ({ - ...prev, - pagespeedApiKey: pagespeedApiKey || "", - })); - }, [pagespeedApiKey]); + if (pagespeedApiKey) { + setIsApiKeySet(true); + setForm((prev) => ({ + ...prev, + pagespeedApiKey: "********", + })); + } else { + setIsApiKeySet(false); + setForm((prev) => ({ + ...prev, + pagespeedApiKey: "", + })); + } + }, [pagespeedApiKey]); const handleChange = (event) => { const { type, checked, value, id } = event.target; From d963fe65c1a582d29063c905fe3ac753da6d2fa9 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 13:53:45 -0400 Subject: [PATCH 48/63] add handler function to reset api key --- client/src/Pages/Settings/index.jsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 77ce770bd..834d7d4b6 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -215,6 +215,14 @@ const Settings = () => { } }; + const handleResetApiKey = () => { + setIsApiKeySet(false); + setForm((prev) => ({ + ...prev, + pagespeedApiKey: "", + })); + }; + const languages = Object.keys(i18n.options.resources || {}); return ( From f2e8f16af8ac1ede6bacdfba1d4e4f18b2655544 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 13:55:48 -0400 Subject: [PATCH 49/63] update pagespeed input field jsx --- client/src/Pages/Settings/index.jsx | 46 +++++++++++++++++++---------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 834d7d4b6..b2f90f554 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -321,22 +321,38 @@ const Settings = () => { - + + + ) + } /> - } - /> + + {isApiKeySet && ( + + )} + {isAdmin && ( From e7742f9be8b7c129dc0ef5091050f780382fd3a9 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 14:17:47 -0400 Subject: [PATCH 50/63] update helpertext and add typography component to display note --- client/src/Pages/Settings/index.jsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index b2f90f554..f1413c2b5 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -96,7 +96,7 @@ const Settings = () => { setIsApiKeySet(true); setForm((prev) => ({ ...prev, - pagespeedApiKey: "********", + pagespeedApiKey: "*************************************", })); } else { setIsApiKeySet(false); @@ -332,11 +332,7 @@ const Settings = () => { disabled={isApiKeySet} optionalLabel="(Optional)" error={!!errors.pagespeedApiKey} - helperText={ - isApiKeySet - ? "API key is set. Click Reset to change it." - : errors.pagespeedApiKey - } + helperText={errors.pagespeedApiKey} endAdornment={ !isApiKeySet && ( { ) } /> + {isApiKeySet && ( + + API key is set. Click Reset to change it. + + )} {isApiKeySet && ( - )} From eb380ce8ccd1239955256d7eb40faaf55604a924 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 7 May 2025 11:36:42 -0700 Subject: [PATCH 51/63] fix status box alignment --- client/src/Components/StatusBoxes/index.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/Components/StatusBoxes/index.jsx b/client/src/Components/StatusBoxes/index.jsx index fedc74011..40ea2d182 100644 --- a/client/src/Components/StatusBoxes/index.jsx +++ b/client/src/Components/StatusBoxes/index.jsx @@ -20,8 +20,8 @@ const StatusBoxes = ({ shouldRender, flexWrap = "nowrap", children }) => { direction="row" flexWrap={flexWrap} gap={theme.spacing(8)} - justifyContent="space-between" - display="flex" + justifyContent="flex-start" + display="flex" > {children} @@ -30,6 +30,7 @@ const StatusBoxes = ({ shouldRender, flexWrap = "nowrap", children }) => { StatusBoxes.propTypes = { shouldRender: PropTypes.bool, + flexWrap: PropTypes.string, children: PropTypes.node, }; From 7c8aea03239a07fb5f60ed47e5b0df7fa0468590 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 14:57:50 -0400 Subject: [PATCH 52/63] add localisation for strings --- client/src/Pages/Settings/index.jsx | 12 ++++++------ client/src/locales/gb.json | 7 ++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index f1413c2b5..34ff60cb2 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -96,7 +96,7 @@ const Settings = () => { setIsApiKeySet(true); setForm((prev) => ({ ...prev, - pagespeedApiKey: "*************************************", + pagespeedApiKey: t("maskedPageSpeedKeyPlaceholder"), })); } else { setIsApiKeySet(false); @@ -315,9 +315,9 @@ const Settings = () => { )} - Google Pagespeed API Key + {t("pageSpeedApiKeyFieldTitle")} - Manage your pagespeed API key + {t("pageSpeedApiKeyFieldDescription")} @@ -325,7 +325,7 @@ const Settings = () => { { } /> {isApiKeySet && ( - - API key is set. Click Reset to change it. + + {t("pageSpeedApiKeyFieldResetLabel")} )} diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index 9deaa9e48..c14f98c1d 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -410,5 +410,10 @@ "validationFailed": "Validation failed", "noFileSelected": "No file selected", "fallbackPage": "Import a file to upload a list of servers in bulk" - } + }, + "maskedPageSpeedKeyPlaceholder": "*************************************", + "pageSpeedApiKeyFieldTitle": "Google PageSpeed API key", + "pageSpeedApiKeyFieldLabel": "PageSpeed API key", + "pageSpeedApiKeyFieldDescription": "Enter your Google PageSpeed API key to enable pagespeed monitoring. Click Reset to update the key.", + "pageSpeedApiKeyFieldResetLabel": "API key is set. Click Reset to change it." } From 376b820ff42284e93143116e978ff60d65acc5ac Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 15:04:08 -0400 Subject: [PATCH 53/63] add spacing between label and input field for textinput component --- client/src/Components/Inputs/TextInput/index.jsx | 1 + client/src/Pages/Settings/index.jsx | 2 +- client/src/locales/gb.json | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/src/Components/Inputs/TextInput/index.jsx b/client/src/Components/Inputs/TextInput/index.jsx index 38a6b6161..2e4313c26 100644 --- a/client/src/Components/Inputs/TextInput/index.jsx +++ b/client/src/Components/Inputs/TextInput/index.jsx @@ -116,6 +116,7 @@ const TextInput = forwardRef( fontSize={"var(--env-var-font-size-medium)"} color={theme.palette.primary.contrastTextSecondary} fontWeight={500} + mb={theme.spacing(2)} > {label} {isRequired && } diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 34ff60cb2..8328dafb3 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -350,7 +350,7 @@ const Settings = () => { {isApiKeySet && ( )} diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index c14f98c1d..1b40dcf56 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -415,5 +415,6 @@ "pageSpeedApiKeyFieldTitle": "Google PageSpeed API key", "pageSpeedApiKeyFieldLabel": "PageSpeed API key", "pageSpeedApiKeyFieldDescription": "Enter your Google PageSpeed API key to enable pagespeed monitoring. Click Reset to update the key.", - "pageSpeedApiKeyFieldResetLabel": "API key is set. Click Reset to change it." + "pageSpeedApiKeyFieldResetLabel": "API key is set. Click Reset to change it.", + "reset": "Reset" } From 51d971929392f594d734f1a44a5819ae7cec58fb Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 15:45:09 -0400 Subject: [PATCH 54/63] update the layout structure to improve UI --- client/src/Pages/Settings/index.jsx | 72 +++++++++++++---------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 8328dafb3..6da0ac68a 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -314,47 +314,41 @@ const Settings = () => { )} - - {t("pageSpeedApiKeyFieldTitle")} - - {t("pageSpeedApiKeyFieldDescription")} - - - - - - - ) - } + + {t("pageSpeedApiKeyFieldTitle")} + + {t("pageSpeedApiKeyFieldDescription")} + + + + - {isApiKeySet && ( - - {t("pageSpeedApiKeyFieldResetLabel")} - - )} - - {isApiKeySet && ( - - )} - + ) + } + /> + {isApiKeySet && ( + + {t("pageSpeedApiKeyFieldResetLabel")} + + )} + {isAdmin && ( From 97f9d91066c1608d087105a99db790a3edf46ef4 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 18:16:59 -0400 Subject: [PATCH 55/63] add useSelector to get pagespeedApiKey --- client/src/Pages/PageSpeed/Monitors/index.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/Pages/PageSpeed/Monitors/index.jsx b/client/src/Pages/PageSpeed/Monitors/index.jsx index 9963e429c..bd8f29586 100644 --- a/client/src/Pages/PageSpeed/Monitors/index.jsx +++ b/client/src/Pages/PageSpeed/Monitors/index.jsx @@ -21,6 +21,7 @@ const PageSpeed = () => { const { t } = useTranslation(); const isAdmin = useIsAdmin(); const { user } = useSelector((state) => state.auth); + const { pagespeedApiKey } = useSelector((state) => state.settings); const { isLoading, monitors, summary, networkError } = useMonitorsFetch({ teamId: user.teamId, From 1a1a5c39d2ebd4910c93214da287029180b70530 Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 18:18:27 -0400 Subject: [PATCH 56/63] update showPageSpeedWarning prop in fallback --- client/src/Pages/PageSpeed/Monitors/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Pages/PageSpeed/Monitors/index.jsx b/client/src/Pages/PageSpeed/Monitors/index.jsx index bd8f29586..bd40aedff 100644 --- a/client/src/Pages/PageSpeed/Monitors/index.jsx +++ b/client/src/Pages/PageSpeed/Monitors/index.jsx @@ -53,7 +53,7 @@ const PageSpeed = () => { ]} link="/pagespeed/create" isAdmin={isAdmin} - showPageSpeedWarning={true} + showPageSpeedWarning={isAdmin && !pagespeedApiKey} /> ); } From ea10e170f4a6783abfa19997db74c034d5d2827e Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 18:23:06 -0400 Subject: [PATCH 57/63] update localized strings --- client/src/Pages/PageSpeed/Monitors/index.jsx | 2 +- client/src/locales/gb.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/Pages/PageSpeed/Monitors/index.jsx b/client/src/Pages/PageSpeed/Monitors/index.jsx index bd40aedff..de5ef79a8 100644 --- a/client/src/Pages/PageSpeed/Monitors/index.jsx +++ b/client/src/Pages/PageSpeed/Monitors/index.jsx @@ -53,7 +53,7 @@ const PageSpeed = () => { ]} link="/pagespeed/create" isAdmin={isAdmin} - showPageSpeedWarning={isAdmin && !pagespeedApiKey} + showPageSpeedWarning={isAdmin} /> ); } diff --git a/client/src/locales/gb.json b/client/src/locales/gb.json index a2db25374..1d0612dca 100644 --- a/client/src/locales/gb.json +++ b/client/src/locales/gb.json @@ -394,8 +394,8 @@ "errorInvalidFieldId": "Invalid field ID provided", "inviteNoTokenFound": "No invite token found", "pageSpeedWarning": "Warning: You haven't added a Google PageSpeed API key. Without it, the PageSpeed monitor won't function.", - "pageSpeedLearnMoreLink": "Click here to learn", - "pageSpeedAddApiKey": "how to add your API key.", + "pageSpeedLearnMoreLink": "Click here to", + "pageSpeedAddApiKey": "add your API key.", "update": "Update", "invalidFileFormat": "Unsupported file format!", "invalidFileSize": "File size is too large!", From 077faa26dd668c09a9b42551dc4f917e1c1df26b Mon Sep 17 00:00:00 2001 From: Vishnu Sreekumaran Nair <200557136@student.georgianc.on.ca> Date: Wed, 7 May 2025 18:28:23 -0400 Subject: [PATCH 58/63] import and use Link to navigate to settings page --- client/src/Components/Fallback/index.jsx | 6 +++--- client/src/locales/gb.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/Components/Fallback/index.jsx b/client/src/Components/Fallback/index.jsx index 18fecd3dd..5b6da7062 100644 --- a/client/src/Components/Fallback/index.jsx +++ b/client/src/Components/Fallback/index.jsx @@ -1,6 +1,7 @@ import PropTypes from "prop-types"; import { useTheme } from "@emotion/react"; import { Box, Button, Stack, Typography, Link } from "@mui/material"; +import { Link as RouterLink } from "react-router-dom"; import Skeleton from "../../assets/Images/create-placeholder.svg?react"; import SkeletonDark from "../../assets/Images/create-placeholder-dark.svg?react"; import Background from "../../assets/Images/background-grid.svg?react"; @@ -35,9 +36,8 @@ const Fallback = ({ title, checks, link = "/", isAdmin, vowelStart = false, show <> {t("pageSpeedWarning")} {" "} Date: Wed, 7 May 2025 18:30:04 -0400 Subject: [PATCH 59/63] add back pagespeedapikey check to showPageSpeedWarning --- client/src/Pages/PageSpeed/Monitors/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Pages/PageSpeed/Monitors/index.jsx b/client/src/Pages/PageSpeed/Monitors/index.jsx index de5ef79a8..bd40aedff 100644 --- a/client/src/Pages/PageSpeed/Monitors/index.jsx +++ b/client/src/Pages/PageSpeed/Monitors/index.jsx @@ -53,7 +53,7 @@ const PageSpeed = () => { ]} link="/pagespeed/create" isAdmin={isAdmin} - showPageSpeedWarning={isAdmin} + showPageSpeedWarning={isAdmin && !pagespeedApiKey} /> ); } From 70ec000266daa9df00a72939a7be30b330532928 Mon Sep 17 00:00:00 2001 From: Aryaman Kumar Sharma Date: Thu, 8 May 2025 17:46:52 +0530 Subject: [PATCH 60/63] Fix: UI Fixes on Infra Page --- .../Details/Components/StatusBoxes/index.jsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/src/Pages/Infrastructure/Details/Components/StatusBoxes/index.jsx b/client/src/Pages/Infrastructure/Details/Components/StatusBoxes/index.jsx index a487dc883..447831acb 100644 --- a/client/src/Pages/Infrastructure/Details/Components/StatusBoxes/index.jsx +++ b/client/src/Pages/Infrastructure/Details/Components/StatusBoxes/index.jsx @@ -51,7 +51,9 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => { subHeading={ <> {physicalCores} - cores + + {physicalCores === 1 ? "core" : "cores"} + } /> @@ -61,7 +63,9 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => { subHeading={ <> {logicalCores} - cores + + {logicalCores === 1 ? "core" : "cores"} + } /> @@ -79,7 +83,7 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => { subHeading={ <> {cpuTemperature.toFixed(2)} - C + °C } /> From c45a282990f49e58a890428f4aec8c9e3a7d5e9c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 8 May 2025 10:39:49 -0700 Subject: [PATCH 61/63] remove text input component styles --- client/src/Components/Inputs/TextInput/index.jsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/client/src/Components/Inputs/TextInput/index.jsx b/client/src/Components/Inputs/TextInput/index.jsx index 38a6b6161..650dc29c5 100644 --- a/client/src/Components/Inputs/TextInput/index.jsx +++ b/client/src/Components/Inputs/TextInput/index.jsx @@ -6,18 +6,6 @@ import PropTypes from "prop-types"; const getSx = (theme, type, maxWidth) => { const sx = { maxWidth: maxWidth, - "& .MuiOutlinedInput-root ": { - "&:hover .MuiOutlinedInput-notchedOutline": { - borderColor: theme.palette.primary.contrastText, // Adjust hover border color - }, - "&.Mui-focused .MuiOutlinedInput-notchedOutline": { - borderColor: theme.palette.accent.main, // Adjust focus border color - }, - "&.Mui-disabled .MuiOutlinedInput-notchedOutline": { - borderColor: theme.palette.primary.contrastText, // CAIO_REVIEW - opacity: 0.5, - }, - }, "& .MuiFormHelperText-root": { position: "absolute", From 002e9ce18abdafbd5bb7806867803292c69a2f3f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 8 May 2025 10:40:17 -0700 Subject: [PATCH 62/63] add colors for borders/disabled borders --- client/src/Utils/Theme/constants.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/client/src/Utils/Theme/constants.js b/client/src/Utils/Theme/constants.js index 8c4127c3d..920a55f69 100644 --- a/client/src/Utils/Theme/constants.js +++ b/client/src/Utils/Theme/constants.js @@ -63,7 +63,6 @@ const paletteColors = { orange500: "#E88C30", orange600: "#DC6803", orange800: "#624711", - }; const semanticColors = { @@ -155,7 +154,6 @@ const newSemanticColors = { light: newColors.blueGray600, dark: newColors.gray200, }, - // CAIO_REVIEW, need a brighter color for dark bg contrastTextSecondaryDarkBg: { light: newColors.gray200, dark: newColors.gray200, @@ -164,6 +162,14 @@ const newSemanticColors = { light: newColors.blueGray500, dark: newColors.gray500, }, + contrastBorder: { + light: newColors.gray500, + dark: newColors.blueGray600, + }, + contrastBorderDisabled: { + light: newColors.gray100, + dark: newColors.blueGray800, + }, lowContrast: { light: newColors.gray200, dark: newColors.blueGray600, @@ -264,7 +270,7 @@ const newSemanticColors = { dark: newColors.red600, }, }, - + /* These are temporary, just for everything not to break */ gradient: { color1: { From d82b0ad67446a2058955d74776d7c6d67f1c58da Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 8 May 2025 10:40:36 -0700 Subject: [PATCH 63/63] apply colors to theme --- client/src/Utils/Theme/globalTheme.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/client/src/Utils/Theme/globalTheme.js b/client/src/Utils/Theme/globalTheme.js index cd8173f83..ff9d1d876 100644 --- a/client/src/Utils/Theme/globalTheme.js +++ b/client/src/Utils/Theme/globalTheme.js @@ -1,5 +1,4 @@ import { typographyLevels } from "./constants"; - const fontFamilyPrimary = '"Inter" , sans-serif'; // const fontFamilySecondary = '"Avenir", sans-serif'; @@ -300,13 +299,15 @@ const baseTheme = (palette) => ({ }), }, }, + MuiTextField: { styleOverrides: { root: ({ theme }) => ({ "& fieldset": { - borderColor: theme.palette.primary.lowContrast, + borderColor: theme.palette.primary.contrastBorder, borderRadius: theme.shape.borderRadius, }, + "& .MuiInputBase-input": { padding: ".75em", minHeight: "var(--env-var-height-2)", @@ -356,10 +357,19 @@ const baseTheme = (palette) => ({ MuiOutlinedInput: { styleOverrides: { root: { - color: palette.primary.contrastTextTertiary, - "&.Mui-focused .MuiOutlinedInput-notchedOutline": { - borderColor: palette.primary.contrastTextTertiary, + "&.Mui-disabled .MuiOutlinedInput-notchedOutline": { + borderColor: palette.primary.contrastBorderDisabled, }, + "&.Mui-disabled:hover .MuiOutlinedInput-notchedOutline": { + borderColor: palette.primary.contrastBorderDisabled, + }, + "&:hover .MuiOutlinedInput-notchedOutline": { + borderColor: palette.primary.contrastText, // Adjust hover border color + }, + "&.Mui-focused .MuiOutlinedInput-notchedOutline": { + borderColor: palette.accent.main, // Adjust focus border color + }, + color: palette.primary.contrastTextTertiary, }, }, }, @@ -486,7 +496,7 @@ const baseTheme = (palette) => ({ root: ({ theme }) => ({ ml: "auto", "& .MuiButtonBase-root, & .MuiButtonBase-root:hover": { - borderColor: theme.palette.primary.lowContrast, + borderColor: theme.palette.primary.contrastBorder, width: "auto", whiteSpace: "nowrap", },