From 64438020243d4671a526af0f7b1ef9d8eb14d4ef Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 17:21:32 +0000 Subject: [PATCH 01/58] cleanup imports --- client/src/Routes/index.jsx | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx index 7d9163c43..0022187fe 100644 --- a/client/src/Routes/index.jsx +++ b/client/src/Routes/index.jsx @@ -11,7 +11,7 @@ import NotFound from "@/Pages/NotFound"; import AuthLogin from "@/Pages/Auth/Login"; import AuthRegister from "@/Pages/Auth/Register"; import AuthForgotPassword from "@/Pages/Auth/Recovery"; -import AuthSetNewPassword from "../Pages/Auth/SetNewPassword"; +import AuthSetNewPassword from "@/Pages/Auth/SetNewPassword"; // Uptime import Uptime from "@/Pages/Uptime/Monitors"; @@ -23,34 +23,34 @@ import PageSpeedDetails from "@/Pages/PageSpeed/Details/"; // Infrastructure import Infrastructure from "@/Pages/Infrastructure/Monitors"; -import InfrastructureDetails from "@/Pages/Infrastructure/Details/index"; +import InfrastructureDetails from "@/Pages/Infrastructure/Details"; // Checks -import Checks from "../Pages/Checks/index"; +import Checks from "@/Pages/Checks"; // Incidents -import Incidents from "../Pages/Incidents/"; +import Incidents from "@/Pages/Incidents"; // Status pages -import CreateStatus from "../Pages/StatusPage/Create/"; -import StatusPages from "../Pages/StatusPage/StatusPages"; -import Status from "../Pages/StatusPage/Status"; +import CreateStatus from "@/Pages/StatusPage/Create/"; +import StatusPages from "@/Pages/StatusPage/StatusPages"; +import Status from "@/Pages/StatusPage/Status"; -import Notifications from "../Pages/Notifications"; -import CreateNotifications from "../Pages/Notifications/create"; +import Notifications from "@/Pages/Notifications"; +import CreateNotifications from "@/Pages/Notifications/create"; // Settings import Account from "@/Pages/Account"; -import EditUser from "../Pages/Account/EditUser"; -import Settings from "../Pages/Settings"; +import EditUser from "@/Pages/Account/EditUser"; +import Settings from "@/Pages/Settings"; -import Maintenance from "../Pages/Maintenance"; +import Maintenance from "@/Pages/Maintenance"; import CreateNewMaintenanceWindow from "@/Pages/Maintenance/create"; -import ProtectedRoute from "../Components/v1/ProtectedRoute"; -import RoleProtectedRoute from "../Components/v1/RoleProtectedRoute"; +import ProtectedRoute from "@/Components/v1/ProtectedRoute"; +import RoleProtectedRoute from "@/Components/v1/RoleProtectedRoute"; import withAdminCheck from "@/Components/v1/HOC/withAdminCheck"; -import Logs from "../Pages/Logs"; +import Logs from "@/Pages/Logs"; import CreateMonitor from "@/Pages/CreateMonitor"; From ee3062fcb495035bb653e68888103d7df4780272 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 17:37:50 +0000 Subject: [PATCH 02/58] remove unused components --- client/src/Components/v1/Alert/index.css | 9 -- client/src/Components/v1/Alert/index.jsx | 138 ------------------ .../v1/ThemeSwitch/SunAndMoonIcon.jsx | 98 ------------- .../src/Components/v1/ThemeSwitch/index.css | 64 -------- .../src/Components/v1/ThemeSwitch/index.jsx | 53 ------- .../Components/v2/routing/RouteProtected.tsx | 0 .../v2/routing/RouteRoleProtected.tsx | 0 client/src/Routes/index.jsx | 4 +- 8 files changed, 1 insertion(+), 365 deletions(-) delete mode 100644 client/src/Components/v1/Alert/index.css delete mode 100644 client/src/Components/v1/Alert/index.jsx delete mode 100644 client/src/Components/v1/ThemeSwitch/SunAndMoonIcon.jsx delete mode 100644 client/src/Components/v1/ThemeSwitch/index.css delete mode 100644 client/src/Components/v1/ThemeSwitch/index.jsx create mode 100644 client/src/Components/v2/routing/RouteProtected.tsx create mode 100644 client/src/Components/v2/routing/RouteRoleProtected.tsx diff --git a/client/src/Components/v1/Alert/index.css b/client/src/Components/v1/Alert/index.css deleted file mode 100644 index 233b5c466..000000000 --- a/client/src/Components/v1/Alert/index.css +++ /dev/null @@ -1,9 +0,0 @@ -.alert { - margin: 0; - width: fit-content; -} -.alert, -.alert button, -.alert .MuiTypography-root { - font-size: var(--env-var-font-size-medium); -} diff --git a/client/src/Components/v1/Alert/index.jsx b/client/src/Components/v1/Alert/index.jsx deleted file mode 100644 index dd3b2f9f2..000000000 --- a/client/src/Components/v1/Alert/index.jsx +++ /dev/null @@ -1,138 +0,0 @@ -import PropTypes from "prop-types"; -import { useTheme } from "@emotion/react"; -import { Box, Button, IconButton, Stack, Typography } from "@mui/material"; -import Icon from "../Icon"; -import "./index.css"; - -/** - * Icons mapping for different alert variants. - * @type {Object} - */ - -const icons = { - info: ( - - ), - error: ( - - ), - warning: ( - - ), -}; - -/** - * @param {Object} props - * @param {'info' | 'error' | 'warning'} props.variant - The type of alert. - * @param {string} [props.title] - The title of the alert. - * @param {string} [props.body] - The body text of the alert. - * @param {boolean} [props.isToast] - Indicates if the alert is used as a toast notification. - * @param {boolean} [props.hasIcon] - Whether to display an icon in the alert. - * @param {function} props.onClick - Toast dismiss function. - * @returns {JSX.Element} - */ - -const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => { - const theme = useTheme(); - /* TODO - Do we need other variants for alert? - */ - - const text = theme.palette.secondary.contrastText; - const border = theme.palette.alert.contrastText; - const bg = theme.palette.alert.main; - const icon = icons[variant]; - - return ( - - {hasIcon && {icon}} - - {title && ( - {title} - )} - {body && ( - {body} - )} - {hasIcon && isToast && ( - - )} - - {isToast && ( - - - - )} - - ); -}; - -Alert.propTypes = { - variant: PropTypes.oneOf(["info", "error", "warning"]).isRequired, - title: PropTypes.string, - body: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - isToast: PropTypes.bool, - hasIcon: PropTypes.bool, - onClick: function (props, propName, componentName) { - if (props.isToast && !props[propName]) { - return new Error( - `Prop '${propName}' is required when 'isToast' is true in '${componentName}'.` - ); - } - return null; - }, -}; - -export default Alert; diff --git a/client/src/Components/v1/ThemeSwitch/SunAndMoonIcon.jsx b/client/src/Components/v1/ThemeSwitch/SunAndMoonIcon.jsx deleted file mode 100644 index 21256e114..000000000 --- a/client/src/Components/v1/ThemeSwitch/SunAndMoonIcon.jsx +++ /dev/null @@ -1,98 +0,0 @@ -import { useTheme } from "@mui/material"; -import "./index.css"; - -const SunAndMoonIcon = () => { - const theme = useTheme(); - - return ( - - ); -}; - -export default SunAndMoonIcon; diff --git a/client/src/Components/v1/ThemeSwitch/index.css b/client/src/Components/v1/ThemeSwitch/index.css deleted file mode 100644 index d5db1c1ca..000000000 --- a/client/src/Components/v1/ThemeSwitch/index.css +++ /dev/null @@ -1,64 +0,0 @@ -.sun-and-moon > :is(.moon, .sun, .sun-beams) { - transform-origin: center; -} - -.theme-toggle .sun-and-moon > .sun-beams { - stroke-width: 2px; -} - -.theme-dark .sun-and-moon > .sun { - transform: scale(1.75); -} - -.theme-dark .sun-and-moon > .sun-beams { - opacity: 0; -} - -.theme-dark .sun-and-moon > .moon > circle { - transform: translateX(-7px); -} - -@supports (cx: 1) { - .theme-dark .sun-and-moon > .moon > circle { - cx: 17; - transform: translateX(0); - } -} - -@media (prefers-reduced-motion: no-preference) { - .sun-and-moon > .sun { - transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); - } - - .sun-and-moon > .sun-beams { - transition: - transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55), - opacity 0.5s cubic-bezier(0.25, 0.1, 0.25, 1); - } - - .sun-and-moon .moon > circle { - transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1); - } - - @supports (cx: 1) { - .sun-and-moon .moon > circle { - transition: cx 0.25s cubic-bezier(0.4, 0, 0.2, 1); - } - } - - .theme-dark .sun-and-moon > .sun { - transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); - transition-duration: 0.25s; - transform: scale(1.75); - } - - .theme-dark .sun-and-moon > .sun-beams { - transition-duration: 0.15s; - transform: rotateZ(-25deg); - } - - .theme-dark .sun-and-moon > .moon > circle { - transition-duration: 0.5s; - transition-delay: 0.25s; - } -} diff --git a/client/src/Components/v1/ThemeSwitch/index.jsx b/client/src/Components/v1/ThemeSwitch/index.jsx deleted file mode 100644 index 60763da90..000000000 --- a/client/src/Components/v1/ThemeSwitch/index.jsx +++ /dev/null @@ -1,53 +0,0 @@ -/** - * ThemeSwitch Component - * Dark and Light Theme Switch - * Original Code: https://web.dev/patterns/theming/theme-switch - * License: Apache License 2.0 - * Copyright © Google LLC - * - * This code has been adapted for use in this project. - * Apache License: https://www.apache.org/licenses/LICENSE-2.0 - */ - -import { IconButton } from "@mui/material"; -import SunAndMoonIcon from "./SunAndMoonIcon.jsx"; -import { useDispatch, useSelector } from "react-redux"; -import { setMode } from "../../../Features/UI/uiSlice.js"; -import "./index.css"; -import { useTranslation } from "react-i18next"; - -const ThemeSwitch = ({ width = 48, height = 48, color }) => { - const mode = useSelector((state) => state.ui.mode); - const dispatch = useDispatch(); - const { t } = useTranslation(); - - const toggleTheme = () => { - dispatch(setMode(mode === "light" ? "dark" : "light")); - }; - - return ( - :is(circle, g)": { - fill: color, - stroke: color, - }, - }} - > - - - ); -}; - -export default ThemeSwitch; diff --git a/client/src/Components/v2/routing/RouteProtected.tsx b/client/src/Components/v2/routing/RouteProtected.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/Components/v2/routing/RouteRoleProtected.tsx b/client/src/Components/v2/routing/RouteRoleProtected.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx index 0022187fe..178d00b2d 100644 --- a/client/src/Routes/index.jsx +++ b/client/src/Routes/index.jsx @@ -49,14 +49,12 @@ import CreateNewMaintenanceWindow from "@/Pages/Maintenance/create"; import ProtectedRoute from "@/Components/v1/ProtectedRoute"; import RoleProtectedRoute from "@/Components/v1/RoleProtectedRoute"; -import withAdminCheck from "@/Components/v1/HOC/withAdminCheck"; import Logs from "@/Pages/Logs"; import CreateMonitor from "@/Pages/CreateMonitor"; const Routes = () => { const mode = useSelector((state) => state.ui.mode); - const AdminCheckedRegister = withAdminCheck(AuthRegister); const v2theme = mode === "light" ? lightTheme : darkTheme; return ( @@ -380,7 +378,7 @@ const Routes = () => { element={ <> - + } From de447d7be2a90e0a77125674c534fab34e92affd Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 17:52:26 +0000 Subject: [PATCH 03/58] move admin check to regsiter page --- .../src/Components/v1/HOC/withAdminCheck.jsx | 49 ------------------- .../Components/v2/routing/RouteProtected.tsx | 41 ++++++++++++++++ .../v2/routing/RouteRoleProtected.tsx | 0 client/src/Pages/Auth/Register/index.tsx | 14 +++++- client/src/Routes/index.jsx | 9 +++- 5 files changed, 61 insertions(+), 52 deletions(-) delete mode 100644 client/src/Components/v1/HOC/withAdminCheck.jsx delete mode 100644 client/src/Components/v2/routing/RouteRoleProtected.tsx diff --git a/client/src/Components/v1/HOC/withAdminCheck.jsx b/client/src/Components/v1/HOC/withAdminCheck.jsx deleted file mode 100644 index 6343b2e4e..000000000 --- a/client/src/Components/v1/HOC/withAdminCheck.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; - -import { logger } from "../../../Utils/Logger.js"; -import { useLazyGet } from "@/Hooks/UseApi"; - -const withAdminCheck = (WrappedComponent) => { - const WithAdminCheck = (props) => { - const navigate = useNavigate(); - const [superAdminExists, setSuperAdminExists] = useState(false); - const [hasChecked, setHasChecked] = useState(false); - const { get: checkSuperAdmin, loading: isChecking } = useLazyGet(); - - useEffect(() => { - checkSuperAdmin("/auth/users/superadmin") - .then((response) => { - if (response?.data === true) { - navigate("/login"); - } else { - setSuperAdminExists(false); - } - }) - .catch((error) => { - logger.error(error); - }) - .finally(() => { - setHasChecked(true); - }); - }, [navigate, checkSuperAdmin]); - - if (!hasChecked || isChecking) { - return null; - } - - return ( - - ); - }; - const wrappedComponentName = - WrappedComponent.displayName || WrappedComponent.name || "Component"; - WithAdminCheck.displayName = `WithAdminCheck(${wrappedComponentName})`; - - return WithAdminCheck; -}; - -export default withAdminCheck; diff --git a/client/src/Components/v2/routing/RouteProtected.tsx b/client/src/Components/v2/routing/RouteProtected.tsx index e69de29bb..7064c26a4 100644 --- a/client/src/Components/v2/routing/RouteProtected.tsx +++ b/client/src/Components/v2/routing/RouteProtected.tsx @@ -0,0 +1,41 @@ +import { Navigate } from "react-router-dom"; +import { useSelector } from "react-redux"; +import type { RootState } from "@/Types/state"; +import type { UserRole } from "@/Types/User"; + +interface ProtectedRouteProps { + children: React.ReactNode; +} + +export const ProtectedRoute = ({ children }: ProtectedRouteProps) => { + const authState = useSelector((state: RootState) => state.auth); + + return authState.authToken ? ( + children + ) : ( + + ); +}; + +interface RoleProtectedRouteProps { + roles: UserRole[]; + children: React.ReactNode; +} + +export const RoleProtectedRoute = ({ roles, children }: RoleProtectedRouteProps) => { + const authState = useSelector((state: RootState) => state.auth); + const userRoles = authState?.user?.role || []; + const canAccess = userRoles.some((role) => roles.includes(role)); + + return canAccess ? ( + children + ) : ( + + ); +}; diff --git a/client/src/Components/v2/routing/RouteRoleProtected.tsx b/client/src/Components/v2/routing/RouteRoleProtected.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/src/Pages/Auth/Register/index.tsx b/client/src/Pages/Auth/Register/index.tsx index 75d27649f..3c8a4e4bc 100644 --- a/client/src/Pages/Auth/Register/index.tsx +++ b/client/src/Pages/Auth/Register/index.tsx @@ -5,7 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod/dist/zod.js"; import { useRegisterForm } from "@/Hooks/useRegisterForm"; import type { RegisterFormData } from "@/Validation/register"; import { useTranslation } from "react-i18next"; -import { usePost } from "@/Hooks/UseApi"; +import { usePost, useGet } from "@/Hooks/UseApi"; import { setAuthState } from "@/Features/Auth/authSlice"; import { useDispatch } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; @@ -32,11 +32,21 @@ const RegisterPage = () => { const { post: verifyToken } = usePost<{ token: string }, InviteVerifyResponse>(); const hasVerified = useRef(false); + const { data: superAdminExists, isLoading: isCheckingAdmin } = useGet( + token ? null : "/auth/users/superadmin" + ); + const { control, handleSubmit, setError, reset } = useForm({ resolver: zodResolver(schema), defaultValues: defaults, }); + useEffect(() => { + if (superAdminExists === true) { + navigate("/login", { replace: true }); + } + }, [superAdminExists, navigate]); + useEffect(() => { if (!token || hasVerified.current) return; hasVerified.current = true; @@ -53,6 +63,8 @@ const RegisterPage = () => { }); }, [token]); + if (isCheckingAdmin) return null; + const onSubmit = async (data: RegisterFormData) => { if (loading) return; diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx index 178d00b2d..3b0b76fc6 100644 --- a/client/src/Routes/index.jsx +++ b/client/src/Routes/index.jsx @@ -47,10 +47,15 @@ import Settings from "@/Pages/Settings"; import Maintenance from "@/Pages/Maintenance"; import CreateNewMaintenanceWindow from "@/Pages/Maintenance/create"; -import ProtectedRoute from "@/Components/v1/ProtectedRoute"; -import RoleProtectedRoute from "@/Components/v1/RoleProtectedRoute"; +// Logs & Diagnostics import Logs from "@/Pages/Logs"; +// Routing +import { + ProtectedRoute, + RoleProtectedRoute, +} from "@/Components/v2/routing/RouteProtected"; + import CreateMonitor from "@/Pages/CreateMonitor"; const Routes = () => { From 6f6920f3b25425c244146a9b6ee09f610709bc36 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 18:15:26 +0000 Subject: [PATCH 04/58] migrate protected routes --- .../Components/v1/ProtectedRoute/index.jsx | 32 ----------------- .../v1/RoleProtectedRoute/index.jsx | 35 ------------------- 2 files changed, 67 deletions(-) delete mode 100644 client/src/Components/v1/ProtectedRoute/index.jsx delete mode 100644 client/src/Components/v1/RoleProtectedRoute/index.jsx diff --git a/client/src/Components/v1/ProtectedRoute/index.jsx b/client/src/Components/v1/ProtectedRoute/index.jsx deleted file mode 100644 index 313500338..000000000 --- a/client/src/Components/v1/ProtectedRoute/index.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Navigate } from "react-router-dom"; -import { useSelector } from "react-redux"; -import PropTypes from "prop-types"; - -/** - * ProtectedRoute is a wrapper component that ensures only authenticated users - * can access the wrapped content. It checks authentication status (e.g., from Redux or Context). - * If the user is authenticated, it renders the children; otherwise, it redirects to the login page. - * - * @param {Object} props - The props passed to the ProtectedRoute component. - * @param {React.ReactNode} props.children - The children to render if the user is authenticated. - * @returns {React.ReactElement} The children wrapped in a protected route or a redirect to the login page. - */ - -const ProtectedRoute = ({ children }) => { - const authState = useSelector((state) => state.auth); - - return authState.authToken ? ( - children - ) : ( - - ); -}; - -ProtectedRoute.propTypes = { - children: PropTypes.element.isRequired, -}; - -export default ProtectedRoute; diff --git a/client/src/Components/v1/RoleProtectedRoute/index.jsx b/client/src/Components/v1/RoleProtectedRoute/index.jsx deleted file mode 100644 index c7b7dfc12..000000000 --- a/client/src/Components/v1/RoleProtectedRoute/index.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Navigate } from "react-router-dom"; -import { useSelector } from "react-redux"; -import PropTypes from "prop-types"; - -/** - * ProtectedRoute is a wrapper component that ensures only authenticated users - * can access the wrapped content. It checks authentication status (e.g., from Redux or Context). - * If the user is authenticated, it renders the children; otherwise, it redirects to the login page. - * - * @param {Object} props - The props passed to the ProtectedRoute component. - * @param {React.ReactNode} props.children - The children to render if the user is authenticated. - * @returns {React.ReactElement} The children wrapped in a protected route or a redirect to the login page. - */ - -const RoleProtectedRoute = ({ roles, children }) => { - const authState = useSelector((state) => state.auth); - const userRoles = authState?.user?.role || []; - const canAccess = userRoles.some((role) => roles.includes(role)); - - return canAccess ? ( - children - ) : ( - - ); -}; - -RoleProtectedRoute.propTypes = { - children: PropTypes.element.isRequired, - roles: PropTypes.array, -}; - -export default RoleProtectedRoute; From e214d9a54ce96bb1972fd4cb8934550caf45d6a1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 18:34:55 +0000 Subject: [PATCH 05/58] sidebar tweak --- .../src/Components/v2/sidebar/Authfooter.tsx | 2 +- client/src/Components/v2/sidebar/index.tsx | 134 ++++++++++-------- 2 files changed, 73 insertions(+), 63 deletions(-) diff --git a/client/src/Components/v2/sidebar/Authfooter.tsx b/client/src/Components/v2/sidebar/Authfooter.tsx index 62ea5610b..4724ed97d 100644 --- a/client/src/Components/v2/sidebar/Authfooter.tsx +++ b/client/src/Components/v2/sidebar/Authfooter.tsx @@ -76,7 +76,7 @@ export const AuthFooter = ({ collapsed, accountMenuItems }: AuthFooterProps) => alignItems="center" py={theme.spacing(4)} px={theme.spacing(8)} - gap={theme.spacing(2)} + gap={theme.spacing(4)} > { }; return ( - t.zIndex.drawer : "auto", - }} - > - + dispatch(setCollapsed({ collapsed: true }))} + sx={{ zIndex: 999 }} + /> + - - {menu.map((item) => { - const selected = location.pathname.startsWith(`/${item.path}`); - return ( - handleNavClick(item.path)} - /> - ); - })} - - - - {bottomMenu.map((item) => { - const selected = location.pathname.startsWith(`/${item.path}`); - return ( - handleNavClick(item.path)} - /> - ); - })} - - + + + {menu.map((item) => { + const selected = location.pathname.startsWith(`/${item.path}`); + return ( + handleNavClick(item.path)} + /> + ); + })} + + + + {bottomMenu.map((item) => { + const selected = location.pathname.startsWith(`/${item.path}`); + return ( + handleNavClick(item.path)} + /> + ); + })} + + - - + + + ); }; From 446c791f88b7d1899add15e623512058ed00e838 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 18:36:20 +0000 Subject: [PATCH 06/58] avatar text color --- client/src/Components/v2/design-elements/Avatar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/Components/v2/design-elements/Avatar.tsx b/client/src/Components/v2/design-elements/Avatar.tsx index 74c06f8f3..2dd1160ad 100644 --- a/client/src/Components/v2/design-elements/Avatar.tsx +++ b/client/src/Components/v2/design-elements/Avatar.tsx @@ -31,6 +31,7 @@ export const Avatar = ({ src, small, sx, onClick = () => {} }: AvatarProps) => { alt={`${user?.firstName} ${user?.lastName}`} src={src ? src : user?.avatarImage ? image : undefined} sx={{ + color: theme.palette.primary.contrastText, fontSize: small ? "16px" : "22px", fontWeight: 400, backgroundColor: theme.palette.primary.main, From d296aec02ea0f6a48b35aa82b553aee5c40c8ed1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 18:44:21 +0000 Subject: [PATCH 07/58] add monitor statuses --- server/src/types/monitor.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index f6c0f83a7..6d1f9a422 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -1,10 +1,12 @@ -import type { Check } from "@/types/check.js"; import type { CheckSnapshot } from "@/types/check.js"; export type { CheckSnapshot } from "@/types/check.js"; export const MonitorTypes = ["http", "ping", "pagespeed", "hardware", "docker", "port", "game", "unknown"] as const; export type MonitorType = (typeof MonitorTypes)[number]; +export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance"] as const; +export type MonitorStatus = (typeof MonitorStatuses)[number]; + export interface MonitorThresholds { usage_cpu?: number; usage_memory?: number; @@ -20,7 +22,7 @@ export interface Monitor { teamId: string; name: string; description?: string; - status?: boolean; + status?: MonitorStatus; statusWindow: boolean[]; statusWindowSize: number; statusWindowThreshold: number; From 7b658a9e52e50986562ce7417bbd1af77ef88f33 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 18:58:12 +0000 Subject: [PATCH 08/58] initial commit --- server/src/db/models/Monitor.ts | 10 ++-- .../monitors/MongoMonitorsRepository.ts | 56 ++++++------------- server/src/types/monitor.ts | 2 +- 3 files changed, 22 insertions(+), 46 deletions(-) diff --git a/server/src/db/models/Monitor.ts b/server/src/db/models/Monitor.ts index d4cc9a872..9111ce47f 100644 --- a/server/src/db/models/Monitor.ts +++ b/server/src/db/models/Monitor.ts @@ -1,9 +1,6 @@ import { Schema, model, Types, type UpdateQuery } from "mongoose"; import type { Monitor, MonitorMatchMethod, MonitorThresholds, CheckSnapshot } from "@/types/monitor.js"; -import { MonitorTypes } from "@/types/monitor.js"; -import Check from "./Check.js"; -import MonitorStats from "./MonitorStats.js"; -import StatusPage from "./StatusPage.js"; +import { MonitorTypes, MonitorStatuses } from "@/types/monitor.js"; type CheckSnapshotDocument = Omit & { createdAt: Date }; @@ -68,8 +65,9 @@ const MonitorSchema = new Schema( type: String, }, status: { - type: Boolean, - default: undefined, + type: String, + enum: MonitorStatuses, + default: "initializing", }, statusWindow: { type: [Boolean], diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index 9b30e5ac2..71bdca752 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -55,7 +55,7 @@ class MongoMonitorsRepository implements IMonitorsRepository { query.isActive = filter === "true"; break; case "status": - query.status = filter === "true"; + query.status = filter; break; case "type": query.type = filter; @@ -223,17 +223,27 @@ class MongoMonitorsRepository implements IMonitorsRepository { totalMonitors: { $sum: 1 }, upMonitors: { $sum: { - $cond: [{ $eq: ["$status", true] }, 1, 0], + $cond: [{ $eq: ["$status", "up"] }, 1, 0], }, }, downMonitors: { $sum: { - $cond: [{ $eq: ["$status", false] }, 1, 0], + $cond: [{ $eq: ["$status", "down"] }, 1, 0], }, }, pausedMonitors: { $sum: { - $cond: [{ $eq: ["$isActive", false] }, 1, 0], + $cond: [{ $eq: ["$status", "paused"] }, 1, 0], + }, + }, + initializingMonitors: { + $sum: { + $cond: [{ $eq: ["$status", "initializing"] }, 1, 0], + }, + }, + maintenanceMonitors: { + $sum: { + $cond: [{ $eq: ["$status", "maintenance"] }, 1, 0], }, }, }, @@ -242,7 +252,7 @@ class MongoMonitorsRepository implements IMonitorsRepository { ]; const [summary] = await MonitorModel.aggregate(pipeline); - return summary ?? { totalMonitors: 0, upMonitors: 0, downMonitors: 0, pausedMonitors: 0 }; + return summary ?? { totalMonitors: 0, upMonitors: 0, downMonitors: 0, pausedMonitors: 0, initializingMonitors: 0, maintenanceMonitors: 0 }; }; findGroupsByTeamId = async (teamId: string): Promise => { @@ -284,7 +294,7 @@ class MongoMonitorsRepository implements IMonitorsRepository { teamId: toStringId(doc.teamId), name: doc.name, description: doc.description ?? undefined, - status: doc.status ?? undefined, + status: doc.status ?? "initializing", statusWindow: doc.statusWindow ?? [], statusWindowSize: doc.statusWindowSize, statusWindowThreshold: doc.statusWindowThreshold, @@ -331,45 +341,13 @@ class MongoMonitorsRepository implements IMonitorsRepository { const notificationIds = (doc.notifications ?? []).map((notification: unknown) => toStringId(notification)); - const checks: Check[] = (doc.checks ?? []).map((check: any) => ({ - id: toStringId(check._id), - metadata: { - monitorId: toStringId(check.metadata?.monitorId), - teamId: toStringId(check.metadata?.teamId), - type: check.metadata?.type, - }, - status: check.status, - responseTime: check.responseTime, - timings: check.timings, - statusCode: check.statusCode, - message: check.message, - ack: check.ack, - ackAt: check.ackAt ?? null, - expiry: toDateString(check.expiry), - cpu: check.cpu, - memory: check.memory, - disk: check.disk, - host: check.host, - errors: check.errors, - capture: check.capture, - net: check.net, - accessibility: check.accessibility, - bestPractices: check.bestPractices, - seo: check.seo, - performance: check.performance, - audits: check.audits, - __v: check.__v, - createdAt: toDateString(check.createdAt), - updatedAt: toDateString(check.updatedAt), - })); - return { id: toStringId(doc._id), userId: toStringId(doc.userId), teamId: toStringId(doc.teamId), name: doc.name, description: doc.description ?? undefined, - status: doc.status ?? undefined, + status: doc.status ?? "initializing", statusWindow: doc.statusWindow ?? [], statusWindowSize: doc.statusWindowSize, statusWindowThreshold: doc.statusWindowThreshold, diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index 6d1f9a422..f3cd40898 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -22,7 +22,7 @@ export interface Monitor { teamId: string; name: string; description?: string; - status?: MonitorStatus; + status: MonitorStatus; statusWindow: boolean[]; statusWindowSize: number; statusWindowThreshold: number; From d622bce6c141cad8986e89623355f0c4c7854ee1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 19:00:04 +0000 Subject: [PATCH 09/58] update summary type --- client/src/Types/Monitor.ts | 2 ++ server/src/types/monitor.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index 2a0272fdc..dde2c4841 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -66,6 +66,8 @@ export interface MonitorsSummary { upMonitors: number; downMonitors: number; pausedMonitors: number; + initializingMonitors: number; + maintenanceMonitors: number; } export interface MonitorsWithChecksResponse { diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index f3cd40898..384e14fe0 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -58,6 +58,8 @@ export interface MonitorsSummary { upMonitors: number; downMonitors: number; pausedMonitors: number; + initializingMonitors: number; + maintenanceMonitors: number; } export interface MonitorsWithChecksByTeamIdResult { From 94afe19b373ae401d10b743b01a360775206a3d2 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 19:22:35 +0000 Subject: [PATCH 10/58] update services/repositories to reflect new monitorstatus type --- .../monitors/MongoMonitorsRepository.ts | 8 ++++++- .../src/service/business/incidentService.ts | 2 +- .../SuperSimpleQueueHelper.ts | 3 ++- .../notificationProviders/utils.ts | 2 +- .../infrastructure/notificationsService.ts | 12 ++++------ .../service/infrastructure/statusService.ts | 24 ++++++------------- server/src/types/network.ts | 3 ++- 7 files changed, 24 insertions(+), 30 deletions(-) diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index 71bdca752..65d93421e 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -181,7 +181,13 @@ class MongoMonitorsRepository implements IMonitorsRepository { { $set: { isActive: { $not: "$isActive" }, - status: "$$REMOVE", + status: { + $cond: { + if: { $eq: ["$status", "paused"] }, + then: "initializing", + else: "paused", + }, + }, }, }, ], diff --git a/server/src/service/business/incidentService.ts b/server/src/service/business/incidentService.ts index 8116c893a..881f98f56 100644 --- a/server/src/service/business/incidentService.ts +++ b/server/src/service/business/incidentService.ts @@ -46,7 +46,7 @@ class IncidentService { handleIncident = async (monitor: Monitor, code: number): Promise => { const activeIncident = await this.incidentsRepository.findActiveByMonitorId(monitor.id, monitor.teamId); // Monitor is down, create an incident - if (monitor.status === false) { + if (monitor.status === "down") { if (activeIncident) { return activeIncident; } else { diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index cf3824d60..c5a3453b6 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -59,7 +59,7 @@ class SuperSimpleQueueHelper { throw new AppError({ message: "No monitor id", service: SERVICE_NAME, method: "getMonitorJob" }); } - // Step 1. Check for maintenacne window, if found, skip the check + // Step 1. Check for maintenance window, if found, skip the check const maintenanceWindowActive = await this.isInMaintenanceWindow(monitorId, teamId); if (maintenanceWindowActive) { this.logger.debug({ @@ -67,6 +67,7 @@ class SuperSimpleQueueHelper { service: SERVICE_NAME, method: "getMonitorJob", }); + // TODO update monitor status return; } diff --git a/server/src/service/infrastructure/notificationProviders/utils.ts b/server/src/service/infrastructure/notificationProviders/utils.ts index f71933425..2fe22e834 100644 --- a/server/src/service/infrastructure/notificationProviders/utils.ts +++ b/server/src/service/infrastructure/notificationProviders/utils.ts @@ -163,7 +163,7 @@ export const buildHardwareEmail = async (emailService: any, monitor: Monitor, al }; export const buildEmail = async (emailService: any, monitor: Monitor): Promise => { - const template = monitor.status === true ? "serverIsUpTemplate" : "serverIsDownTemplate"; + const template = monitor.status === "up" ? "serverIsUpTemplate" : "serverIsDownTemplate"; const context = { monitor: monitor.name, url: monitor.url }; const html = await emailService.buildEmail(template, context); return html; diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index 78b1dc8ab..531014a7a 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -1,7 +1,8 @@ -import type { HardwareStatusPayload, Monitor, MonitorStatusResponse, Notification } from "@/types/index.js"; +import type { HardwareStatusPayload, Monitor, MonitorStatusResponse, Notification, MonitorStatus } from "@/types/index.js"; import { shouldSendHardwareAlert } from "@/service/infrastructure/notificationProviders/utils.js"; import { IMonitorsRepository, INotificationsRepository } from "@/repositories/index.js"; import { INotificationProvider } from "./notificationProviders/INotificationProvider.js"; + export interface INotificationsService { createNotification: (notificationData: Partial) => Promise; findById: (id: string, teamId: string) => Promise; @@ -11,7 +12,7 @@ export interface INotificationsService { handleNotifications: ( monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, - prevStatus: boolean | undefined, + prevStatus: MonitorStatus, statusChanged: boolean ) => Promise; @@ -228,12 +229,7 @@ export class NotificationsService implements INotificationsService { return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus); }; - handleNotifications = async ( - monitor: Monitor, - monitorStatusResponse: MonitorStatusResponse, - prevStatus: boolean | undefined, - statusChanged: boolean - ) => { + handleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, prevStatus: MonitorStatus, statusChanged: boolean) => { const { type } = monitor; const payload = monitorStatusResponse.payload as HardwareStatusPayload; // If this is a non-hardeware type monitor and status did not change, we're done diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index 0e1011278..506ad5396 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -2,7 +2,6 @@ import { IMonitorsRepository } from "@/repositories/index.js"; import MonitorStats from "../../db/models/MonitorStats.js"; import { CheckModel } from "@/db/models/index.js"; import type { - CheckErrorInfo, Monitor, MonitorStatusResponse, StatusChangeResult, @@ -15,7 +14,6 @@ const SERVICE_NAME = "StatusService"; export interface IStatusService { updateRunningStats({ monitor, networkResponse }: { monitor: Monitor; networkResponse: any }): Promise; - getStatusString(status: boolean | undefined): string; handleIncidentForCheck(check: any, monitor: Monitor, action: any, errorContext?: string): Promise; updateMonitorStatus( statusResponse: MonitorStatusResponse, @@ -39,7 +37,7 @@ export class StatusService implements IStatusService { return StatusService.SERVICE_NAME; } - async updateRunningStats({ monitor, networkResponse }: { monitor: Monitor; networkResponse: any }) { + async updateRunningStats({ monitor, networkResponse }: { monitor: Monitor; networkResponse: MonitorStatusResponse }) { try { const monitorId = monitor.id; const { responseTime, status } = networkResponse; @@ -60,7 +58,7 @@ export class StatusService implements IStatusService { // Update stats // Last response time - stats.lastResponseTime = responseTime; + stats.lastResponseTime = responseTime ?? 0; // Avg response time: let avgResponseTime = stats.avgResponseTime; @@ -111,12 +109,6 @@ export class StatusService implements IStatusService { } } - getStatusString = (status: boolean | undefined) => { - if (status === true) return "up"; - if (status === false) return "down"; - return "unknown"; - }; - handleIncidentForCheck = async (check: Check, monitor: Monitor, action: any, errorContext = "incident handling") => { try { let savedCheck; @@ -208,9 +200,7 @@ export class StatusService implements IStatusService { monitor.recentChecks.shift(); } - if (monitor.status === undefined || monitor.status === null) { - monitor.status = status; - } + monitor.status = status === true ? "up" : "down"; const prevStatus = monitor.status; let newStatus = monitor.status; @@ -233,13 +223,13 @@ export class StatusService implements IStatusService { const failureRate = (failures / monitor.statusWindow.length) * 100; // If threshold has been met and the monitor is not already down, mark down: - if (failureRate >= monitor.statusWindowThreshold && monitor.status !== false) { - newStatus = false; + if (failureRate >= monitor.statusWindowThreshold && monitor.status !== "down") { + newStatus = "down"; statusChanged = true; } // If the failure rate is below the threshold and the monitor is down, recover: - else if (failureRate < monitor.statusWindowThreshold && monitor.status === false) { - newStatus = true; + else if (failureRate < monitor.statusWindowThreshold && monitor.status === "down") { + newStatus = "up"; statusChanged = true; } diff --git a/server/src/types/network.ts b/server/src/types/network.ts index 6bed40316..7fbfb79fe 100644 --- a/server/src/types/network.ts +++ b/server/src/types/network.ts @@ -11,6 +11,7 @@ import type { Monitor, MonitorMatchMethod, MonitorType, + MonitorStatus, } from "@/types/index.js"; export interface MonitorStatusResponse { @@ -106,7 +107,7 @@ export interface MonitorPayloadMap { export type StatusChangeResult = { monitor: Monitor; statusChanged: boolean; - prevStatus: boolean | undefined; + prevStatus: MonitorStatus; code: number; timestamp: number; }; From cbd8b5db47536cfc7cd779da28221168aa2f5006 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 19:38:32 +0000 Subject: [PATCH 11/58] update monitor status on maintenance --- server/src/config/services.ts | 1 + .../SuperSimpleQueue/SuperSimpleQueueHelper.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 4437e9176..9bf18ff1d 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -206,6 +206,7 @@ export const initializeServices = async ({ buffer: bufferService, incidentService, maintenanceWindowsRepository, + monitorsRepository, }); const superSimpleQueue = await SuperSimpleQueue.create({ diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index c5a3453b6..d5d275e59 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -3,7 +3,7 @@ import type { Monitor } from "@/types/monitor.js"; import { AppError } from "@/utils/AppError.js"; import { INetworkService, INotificationsService, IStatusService } from "@/service/index.js"; import IncidentService from "@/service/business/incidentService.js"; -import { IMaintenanceWindowsRepository } from "@/repositories/index.js"; +import { IMaintenanceWindowsRepository, IMonitorsRepository } from "@/repositories/index.js"; class SuperSimpleQueueHelper { static SERVICE_NAME = SERVICE_NAME; @@ -16,6 +16,7 @@ class SuperSimpleQueueHelper { private buffer: any; private incidentService: IncidentService; private maintenanceWindowsRepository: IMaintenanceWindowsRepository; + private monitorsRepository: IMonitorsRepository; constructor({ logger, @@ -26,6 +27,7 @@ class SuperSimpleQueueHelper { buffer, incidentService, maintenanceWindowsRepository, + monitorsRepository, }: { logger: any; networkService: INetworkService; @@ -35,6 +37,7 @@ class SuperSimpleQueueHelper { buffer: any; incidentService: IncidentService; maintenanceWindowsRepository: IMaintenanceWindowsRepository; + monitorsRepository: IMonitorsRepository; }) { this.logger = logger; this.networkService = networkService; @@ -44,6 +47,7 @@ class SuperSimpleQueueHelper { this.notificationsService = notificationsService; this.incidentService = incidentService; this.maintenanceWindowsRepository = maintenanceWindowsRepository; + this.monitorsRepository = monitorsRepository; } get serviceName() { @@ -60,6 +64,7 @@ class SuperSimpleQueueHelper { } // Step 1. Check for maintenance window, if found, skip the check + const maintenanceWindowActive = await this.isInMaintenanceWindow(monitorId, teamId); if (maintenanceWindowActive) { this.logger.debug({ @@ -67,7 +72,9 @@ class SuperSimpleQueueHelper { service: SERVICE_NAME, method: "getMonitorJob", }); - // TODO update monitor status + if (monitor.status !== "maintenance") { + await this.monitorsRepository.updateById(monitorId, teamId, { status: "maintenance" }); + } return; } From 4b1c588f5ad5c02dfeaba676bc11917e0a26c220 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 20:11:22 +0000 Subject: [PATCH 12/58] extract header --- .../v2/design-elements/StatusBox.tsx | 35 ++++++++++++------- .../v2/design-elements/StatusLabel.tsx | 35 +++++++------------ .../v2/monitors/HeaderMonitorsSummary.tsx | 29 +++++++++++++++ client/src/Components/v2/monitors/index.tsx | 1 + .../Pages/Infrastructure/Monitors/index.tsx | 20 +++-------- client/src/Pages/PageSpeed/Monitors/index.tsx | 20 +++-------- .../Status/Components/MonitorsList.tsx | 7 +--- .../Status/Components/StatusBar.tsx | 6 ++-- .../Components/UptimeMonitorsTable.tsx | 7 +--- client/src/Pages/Uptime/Monitors/index.tsx | 25 +++++-------- client/src/Types/Monitor.ts | 12 +++++-- client/src/Utils/MonitorUtils.ts | 21 ++++------- client/src/locales/en.json | 1 + 13 files changed, 105 insertions(+), 114 deletions(-) create mode 100644 client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx diff --git a/client/src/Components/v2/design-elements/StatusBox.tsx b/client/src/Components/v2/design-elements/StatusBox.tsx index bf7979cca..a83ebcf5d 100644 --- a/client/src/Components/v2/design-elements/StatusBox.tsx +++ b/client/src/Components/v2/design-elements/StatusBox.tsx @@ -105,6 +105,29 @@ export const PausedStatusBox = ({ n }: { n: number }) => { /> ); }; +export const MaintenanceStatusBox = ({ n }: { n: number }) => { + const theme = useTheme(); + const { t } = useTranslation(); + return ( + + ); +}; +export const InitializingStatusBox = ({ n }: { n: number }) => { + const theme = useTheme(); + const { t } = useTranslation(); + return ( + + ); +}; + export const TotalChecksBox = ({ n }: { n: number }) => { const theme = useTheme(); const { t } = useTranslation(); @@ -138,15 +161,3 @@ export const UpChecksBox = ({ n }: { n: number }) => { /> ); }; - -export const InitializingStatusBox = ({ n }: { n: number }) => { - const theme = useTheme(); - const { t } = useTranslation(); - return ( - - ); -}; diff --git a/client/src/Components/v2/design-elements/StatusLabel.tsx b/client/src/Components/v2/design-elements/StatusLabel.tsx index d7212ddff..cf404421e 100644 --- a/client/src/Components/v2/design-elements/StatusLabel.tsx +++ b/client/src/Components/v2/design-elements/StatusLabel.tsx @@ -11,33 +11,24 @@ import { useTranslation } from "react-i18next"; export const ValueTypes = ["positive", "negative", "neutral"] as const; export type ValueType = (typeof ValueTypes)[number]; -export const StatusLabel = ({ - status, - isActive, - sx, -}: { - status: MonitorStatus; - isActive?: boolean; - sx?: SxProps; -}) => { +export const StatusLabel = ({ status, sx }: { status: MonitorStatus; sx?: SxProps }) => { const { t } = useTranslation(); const theme = useTheme(); const palette = getStatusPalette(status); - const determineStatus = ( - isActive: boolean | undefined, - status: MonitorStatus - ): string => { - if (isActive === false) { + const determineStatus = (status: MonitorStatus): string => { + if (status === "up") { + return t("pages.common.monitors.status.up"); + } else if (status === "down") { + return t("pages.common.monitors.status.down"); + } else if (status === "maintenance") { + return t("pages.common.monitors.status.maintenance"); + } else if (status === "paused") { return t("pages.common.monitors.status.paused"); + } else if (status === "initializing") { + return t("pages.common.monitors.status.initializing"); } - if (status === true) { - return t("pages.common.monitors.status.up"); - } - if (status === false) { - return t("pages.common.monitors.status.down"); - } return t("pages.common.monitors.status.initializing"); }; @@ -64,9 +55,7 @@ export const StatusLabel = ({ borderRadius="50%" marginRight="5px" /> - - {determineStatus(isActive, status)} - + {determineStatus(status)} ); }; diff --git a/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx b/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx new file mode 100644 index 000000000..b2a93a807 --- /dev/null +++ b/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx @@ -0,0 +1,29 @@ +import { + UpStatusBox, + DownStatusBox, + PausedStatusBox, + InitializingStatusBox, +} from "@/Components/v2/design-elements"; +import Stack from "@mui/material/Stack"; + +import type { MonitorsSummary } from "@/Types/Monitor"; +import { useTheme } from "@mui/material"; + +interface MonitorsSummaryProps { + summary: MonitorsSummary | null; +} + +export const HeaderMonitorsSummary = ({ summary }: MonitorsSummaryProps) => { + const theme = useTheme(); + return ( + + + + + + + ); +}; diff --git a/client/src/Components/v2/monitors/index.tsx b/client/src/Components/v2/monitors/index.tsx index e2856d6a9..9496395f6 100644 --- a/client/src/Components/v2/monitors/index.tsx +++ b/client/src/Components/v2/monitors/index.tsx @@ -11,3 +11,4 @@ export * from "./charts/PiePageSpeedLegend"; export * from "./charts/HistogramPageSpeedDetails"; export * from "./charts/HistogramPageSpeedDetailsTooltip"; export * from "./charts/HistogramInfrastructure"; +export * from "./HeaderMonitorsSummary"; diff --git a/client/src/Pages/Infrastructure/Monitors/index.tsx b/client/src/Pages/Infrastructure/Monitors/index.tsx index 1d38dbdd3..01de1c09c 100644 --- a/client/src/Pages/Infrastructure/Monitors/index.tsx +++ b/client/src/Pages/Infrastructure/Monitors/index.tsx @@ -1,13 +1,8 @@ import Stack from "@mui/material/Stack"; import useMediaQuery from "@mui/material/useMediaQuery"; -import { - MonitorBasePageWithStates, - UpStatusBox, - DownStatusBox, - PausedStatusBox, -} from "@/Components/v2/design-elements"; +import { MonitorBasePageWithStates } from "@/Components/v2/design-elements"; import { HeaderCreate } from "@/Components/v2/common"; -import { ControlsFilter } from "@/Components/v2/monitors"; +import { ControlsFilter, HeaderMonitorsSummary } from "@/Components/v2/monitors"; import { TextField, Dialog } from "@/Components/v2/inputs"; import { useGet, useDelete } from "@/Hooks/UseApi"; @@ -99,7 +94,7 @@ const InfrastructureMonitors = () => { { refreshInterval: 5000, keepPreviousData: true } ); - const { summary, count } = monitorsWithChecksData ?? {}; + const { summary, count } = monitorsWithChecksData ?? { summary: null, count: 0 }; const isLoading = monitorsWithChecksLoading; // Check if any filters are active @@ -138,14 +133,7 @@ const InfrastructureMonitors = () => { isLoading={isLoading} isAdmin={isAdmin} /> - - - - - + { const { t } = useTranslation(); - const theme = useTheme(); const isAdmin = useIsAdmin(); const { deleteFn, loading: isDeleting } = useDelete(); @@ -48,8 +43,8 @@ const PageSpeedMonitorsPage = () => { const [rowsPerPage, setRowsPerPage] = useState(10); const monitors = monitorsData?.monitors; - const monitorsCount = monitorsData?.count; - const summary = monitorsData?.summary; + const monitorsCount = monitorsData?.count ?? 0; + const summary = monitorsData?.summary ?? null; const isLoading = monitorsIsLoading || settingsIsLoading; @@ -80,14 +75,7 @@ const PageSpeedMonitorsPage = () => { isLoading={isLoading} isAdmin={isAdmin} /> - - - - - + { )} {monitors?.map((monitor) => { - const status = determineState(monitor); return ( { )} - + {statusPage.showCharts !== false && ( diff --git a/client/src/Pages/StatusPage/Status/Components/StatusBar.tsx b/client/src/Pages/StatusPage/Status/Components/StatusBar.tsx index 8b3343249..b5c52b32b 100644 --- a/client/src/Pages/StatusPage/Status/Components/StatusBar.tsx +++ b/client/src/Pages/StatusPage/Status/Components/StatusBar.tsx @@ -12,16 +12,16 @@ const getMonitorStatus = (monitors: Monitor[], theme: Theme, t: Function) => { icon: , }; - if (monitors.every((monitor) => monitor.status === true)) { + if (monitors.every((monitor) => monitor.status === "up")) { monitorsStatus.msg = t("pages.statusPages.statusBar.allUp"); monitorsStatus.color = theme.palette.success.main; monitorsStatus.icon = ; return monitorsStatus; - } else if (monitors.every((monitor) => monitor.status === false)) { + } else if (monitors.every((monitor) => monitor.status === "down")) { monitorsStatus.msg = t("pages.statusPages.statusBar.allDown"); monitorsStatus.color = theme.palette.error.main; return monitorsStatus; - } else if (monitors.some((monitor) => monitor.status === false)) { + } else if (monitors.some((monitor) => monitor.status === "down")) { monitorsStatus.msg = t("pages.statusPages.statusBar.degraded"); monitorsStatus.color = theme.palette.warning.main; return monitorsStatus; diff --git a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx index 94c619672..75738e6ad 100644 --- a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx +++ b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx @@ -186,12 +186,7 @@ export const MonitorTable = ({ ), render: (row) => { - return ( - - ); + return ; }, }, { diff --git a/client/src/Pages/Uptime/Monitors/index.tsx b/client/src/Pages/Uptime/Monitors/index.tsx index 702bbd928..9e36ccc86 100644 --- a/client/src/Pages/Uptime/Monitors/index.tsx +++ b/client/src/Pages/Uptime/Monitors/index.tsx @@ -1,10 +1,5 @@ -import { ControlsFilter } from "@/Components/v2/monitors"; -import { - MonitorBasePageWithStates, - UpStatusBox, - DownStatusBox, - PausedStatusBox, -} from "@/Components/v2/design-elements"; +import { ControlsFilter, HeaderMonitorsSummary } from "@/Components/v2/monitors"; +import { MonitorBasePageWithStates } from "@/Components/v2/design-elements"; import { TextField, Dialog } from "@/Components/v2/inputs"; import Stack from "@mui/material/Stack"; import { MonitorTable } from "@/Pages/Uptime/Monitors/Components/UptimeMonitorsTable"; @@ -99,7 +94,11 @@ const UptimeMonitorsPage = () => { { refreshInterval: 5000, keepPreviousData: true } ); - const { monitors: monitorsWithChecks, summary, count } = monitorsWithChecksData ?? {}; + const { + monitors: monitorsWithChecks, + summary, + count, + } = monitorsWithChecksData ?? { monitors: null, summary: null, count: 0 }; // Delete hook const { deleteFn, loading: isDeleting } = useDelete(); @@ -150,14 +149,8 @@ const UptimeMonitorsPage = () => { isLoading={isLoading} isAdmin={isAdmin} /> - - - - - + + { - if (typeof monitor === "undefined") return "pending"; - if (monitor?.isActive === false) return "paused"; - if (monitor?.status === undefined) return "pending"; - return monitor?.status == true ? "up" : "down"; -}; - export const getMonitorPath = (type: MonitorType): string => { const pathMap: Record = { http: "uptime", @@ -24,10 +17,10 @@ export const getMonitorPath = (type: MonitorType): string => { }; export const getStatusPalette = (status: MonitorStatus): PaletteKey => { - if (status === true) { + if (status === "up") { return "success"; } - if (status === false) { + if (status === "down") { return "error"; } return "warning"; @@ -43,11 +36,11 @@ export const getValuePalette = (value: ValueType): PaletteKey => { }; export const getStatusColor = (status: MonitorStatus, theme: any): string => { - if (status === true) { + if (status === "up") { return theme.palette.success.light; } - if (status === false) { + if (status === "down") { return theme.palette.error.light; } @@ -101,9 +94,9 @@ export const getStatusPageHeaderConfig = ( return { paletteKey: "error", message: "No monitors available" }; } - const allUp = monitors.every((monitor) => monitor.status === true); - const anyDown = monitors.some((monitor) => monitor.status === false); - const allDown = monitors.every((monitor) => monitor.status === false); + const allUp = monitors.every((monitor) => monitor.status === "up"); + const anyDown = monitors.some((monitor) => monitor.status === "down"); + const allDown = monitors.every((monitor) => monitor.status === "down"); if (allUp) return { diff --git a/client/src/locales/en.json b/client/src/locales/en.json index d2a066c11..7eb833308 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -775,6 +775,7 @@ "status": { "down": "down", "initializing": "initializing", + "maintenance": "maintenance", "paused": "paused", "total": "total", "up": "up" From 71cdd05b152a64daad9fd18b9e28142221f401df Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 11 Feb 2026 20:29:50 +0000 Subject: [PATCH 13/58] type errors --- client/src/Pages/Checks/Components/ChecksTable.tsx | 4 ++-- .../Infrastructure/Monitors/Components/MonitorsTable.tsx | 7 +------ client/src/Pages/Uptime/Details/Components/ChecksTable.tsx | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/client/src/Pages/Checks/Components/ChecksTable.tsx b/client/src/Pages/Checks/Components/ChecksTable.tsx index 6464be25c..bb1920ab2 100644 --- a/client/src/Pages/Checks/Components/ChecksTable.tsx +++ b/client/src/Pages/Checks/Components/ChecksTable.tsx @@ -6,7 +6,7 @@ import { } from "@/Components/v2/design-elements"; import Box from "@mui/material/Box"; import type { Header } from "@/Components/v2/design-elements/Table"; -import type { Monitor, MonitorStatus } from "@/Types/Monitor"; +import type { Monitor } from "@/Types/Monitor"; import { useTranslation } from "react-i18next"; import { formatDateWithTz } from "@/Utils/TimeUtils"; @@ -52,7 +52,7 @@ export const ChecksTable = ({ id: "status", content: "Status", render: (row) => { - return ; + return ; }, }, { diff --git a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx index ca236f45f..b2bcadc1a 100644 --- a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx +++ b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx @@ -195,12 +195,7 @@ export const InfraMonitorsTable = ({ ), render: (row) => { - return ( - - ); + return ; }, }, { diff --git a/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx b/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx index 2cfdc1f15..ceb8e1a28 100644 --- a/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx +++ b/client/src/Pages/Uptime/Details/Components/ChecksTable.tsx @@ -15,7 +15,7 @@ const getHeaders = (t: Function, uiTimezone: string) => { id: "status", content: t("common.table.headers.status"), render: (row) => { - return ; + return ; }, }, { From 2e30b622d3fb0c06aae8b88d80a6b2a57f853aef Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 17:26:17 +0000 Subject: [PATCH 14/58] put -> patch --- client/src/Pages/Settings/index.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index fb6185784..6e6574963 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -27,7 +27,7 @@ import { import SettingsStats from "./SettingsStats.jsx"; import { useIsAdmin } from "@/Hooks/useIsAdmin.js"; -import { useGet, usePost, useDelete, useLazyGet, usePut } from "@/Hooks/UseApi"; +import { useGet, usePost, useDelete, useLazyGet, usePatch } from "@/Hooks/UseApi"; // Constants const BREADCRUMBS = [{ name: `Settings`, path: "/settings" }]; @@ -62,10 +62,10 @@ const Settings = () => { } }, [fetchedSettings]); - const { put: saveSettingsFn, loading: isSaving } = usePut(); + const { patch: saveSettingsFn, loading: isSaving } = usePatch(); const saveSettings = async (settings) => { - const response = await saveSettingsFn("/settings", { settings }); + const response = await saveSettingsFn("/settings", settings); if (response?.data) { const data = response.data; setIsApiKeySet(data.pagespeedKeySet); From b540e48aabf130d3063e45e036841868971b8f78 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 18:01:12 +0000 Subject: [PATCH 15/58] clean up index.css --- .../src/Components/WalletProvider/index.css | 53 ------ .../src/Components/WalletProvider/index.jsx | 50 ------ .../src/Components/v1/Breadcrumbs/index.css | 1 - .../src/Components/v1/Inputs/Select/index.jsx | 1 - .../v1/Inputs/TextInput/Adornments/index.jsx | 1 - .../v2/design-elements/MonitorStatus.tsx | 2 - .../v2/design-elements/PulseDot.tsx | 17 +- client/src/Pages/Integrations/index.css | 10 -- client/src/Pages/Integrations/index.jsx | 156 ------------------ client/src/Utils/Theme/globalTheme.js | 8 +- client/src/Utils/Theme/v2Theme.ts | 7 + client/src/index.css | 66 -------- 12 files changed, 23 insertions(+), 349 deletions(-) delete mode 100644 client/src/Components/WalletProvider/index.css delete mode 100644 client/src/Components/WalletProvider/index.jsx delete mode 100644 client/src/Pages/Integrations/index.css delete mode 100644 client/src/Pages/Integrations/index.jsx diff --git a/client/src/Components/WalletProvider/index.css b/client/src/Components/WalletProvider/index.css deleted file mode 100644 index f3da31efc..000000000 --- a/client/src/Components/WalletProvider/index.css +++ /dev/null @@ -1,53 +0,0 @@ -.wallet-adapter-dropdown { - width: 100%; - display: flex; - flex-wrap: wrap; - justify-content: center; - align-items: center; - gap: var(--env-var-spacing-1); -} - -.wallet-adapter-button { - display: flex; - align-items: center; - justify-content: center; - width: auto; - height: var(--env-var-height-2) !important; - font-size: var(--env-var-font-size-medium-plus) !important; - font-weight: 500 !important; - margin: 0; - padding: calc( - (var(--env-var-height-2) - var(--env-var-font-size-medium-plus) * 1.2) / 2 - ) - var(--env-var-spacing-1); - white-space: nowrap; -} - -.wallet-adapter-modal-title { - font-size: var(--font-size-h5) !important; -} - -/* Separator styling */ -.wallet-adapter-modal-divider { - background-color: var(--border-color) !important; - margin: var(--spacing-md) 0 !important; -} - -/* Responsive fixes */ -@media (max-width: 1200px) { - .wallet-adapter-button { - font-size: var(--env-var-font-size-medium) !important; - padding: calc((var(--env-var-height-2) - var(--env-var-font-size-medium) * 1.2) / 2) - var(--env-var-spacing-1-minus) !important; - } -} - -@media (max-width: 900px) { - .wallet-adapter-modal-wrapper { - flex-direction: column !important; - } - - .wallet-adapter-modal-divider { - margin: var(--spacing-sm) 0 !important; - } -} diff --git a/client/src/Components/WalletProvider/index.jsx b/client/src/Components/WalletProvider/index.jsx deleted file mode 100644 index 13cc83b07..000000000 --- a/client/src/Components/WalletProvider/index.jsx +++ /dev/null @@ -1,50 +0,0 @@ -// import { useMemo } from "react"; -// import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react"; -// import { WalletAdapterNetwork } from "@solana/wallet-adapter-base"; -// import { -// UnsafeBurnerWalletAdapter, -// PhantomWalletAdapter, -// } from "@solana/wallet-adapter-wallets"; - -// import { WalletModalProvider } from "@solana/wallet-adapter-react-ui"; -// import { clusterApiUrl } from "@solana/web3.js"; -// import PropTypes from "prop-types"; -// import "./index.css"; - -// // Default styles that can be overridden by your app -// import "@solana/wallet-adapter-react-ui/styles.css"; - -// export const Wallet = ({ children }) => { -// // The network can be set to 'devnet', 'testnet', or 'mainnet-beta'. -// const network = WalletAdapterNetwork.Mainnet; - -// // You can also provide a custom RPC endpoint. -// const endpoint = useMemo(() => clusterApiUrl(network), [network]); - -// const wallets = useMemo( -// () => [new PhantomWalletAdapter()], -// // eslint-disable-next-line react-hooks/exhaustive-deps -// [network] -// ); - -// return ( -// -// -// {children} -// -// -// ); -// }; - -// Wallet.propTypes = { -// children: PropTypes.node, -// }; - -const Wallet = ({ children }) => { - return children; -}; - -export default Wallet; diff --git a/client/src/Components/v1/Breadcrumbs/index.css b/client/src/Components/v1/Breadcrumbs/index.css index abb3c0a28..022db9a83 100644 --- a/client/src/Components/v1/Breadcrumbs/index.css +++ b/client/src/Components/v1/Breadcrumbs/index.css @@ -6,7 +6,6 @@ min-height: 16px; } .MuiBreadcrumbs-root .MuiBreadcrumbs-li a { - font-size: var(--env-var-font-size-medium); font-weight: 400; } .MuiBreadcrumbs-root .MuiBreadcrumbs-li:not(:last-child) { diff --git a/client/src/Components/v1/Inputs/Select/index.jsx b/client/src/Components/v1/Inputs/Select/index.jsx index 0f96a2ff6..ec2522d17 100644 --- a/client/src/Components/v1/Inputs/Select/index.jsx +++ b/client/src/Components/v1/Inputs/Select/index.jsx @@ -64,7 +64,6 @@ const Select = ({ const theme = useTheme(); const getItemValue = (item) => item?._id ?? item?.id; const itemStyles = { - fontSize: "var(--env-var-font-size-medium)", color: theme.palette.primary.contrastTextTertiary, borderRadius: theme.shape.borderRadius, margin: theme.spacing(2), diff --git a/client/src/Components/v1/Inputs/TextInput/Adornments/index.jsx b/client/src/Components/v1/Inputs/TextInput/Adornments/index.jsx index 078684405..2b3abab0f 100644 --- a/client/src/Components/v1/Inputs/TextInput/Adornments/index.jsx +++ b/client/src/Components/v1/Inputs/TextInput/Adornments/index.jsx @@ -18,7 +18,6 @@ export const HttpAdornment = ({ https }) => { > diff --git a/client/src/Components/v2/design-elements/MonitorStatus.tsx b/client/src/Components/v2/design-elements/MonitorStatus.tsx index 3d5e81845..09cd95f0f 100644 --- a/client/src/Components/v2/design-elements/MonitorStatus.tsx +++ b/client/src/Components/v2/design-elements/MonitorStatus.tsx @@ -23,7 +23,6 @@ export const MonitorStatus = ({ monitor }: { monitor: Monitor }) => { overflow={"hidden"} textOverflow={"ellipsis"} whiteSpace={"nowrap"} - maxWidth={isSmall ? "100%" : "calc((100vw - var(--env-var-width-2)) / 2)"} > {monitor.name} @@ -40,7 +39,6 @@ export const MonitorStatus = ({ monitor }: { monitor: Monitor }) => { overflow={"hidden"} textOverflow={"ellipsis"} whiteSpace={"nowrap"} - maxWidth={isSmall ? "100%" : "calc((100vw - var(--env-var-width-2)) / 2)"} > {formatUrl(monitor?.url)} diff --git a/client/src/Components/v2/design-elements/PulseDot.tsx b/client/src/Components/v2/design-elements/PulseDot.tsx index ab792b628..1f5b3401e 100644 --- a/client/src/Components/v2/design-elements/PulseDot.tsx +++ b/client/src/Components/v2/design-elements/PulseDot.tsx @@ -1,4 +1,17 @@ -import { Box, Stack, useTheme } from "@mui/material"; +import Box from "@mui/material/Box"; +import Stack from "@mui/material/Stack"; +import { useTheme, keyframes } from "@mui/material"; + +const ripple = keyframes` + from { + opacity: 1; + transform: scale(0); + } + to { + opacity: 0; + transform: scale(2); + } +`; interface PulseDotProps { color: string; @@ -28,7 +41,7 @@ export const PulseDot = ({ color }: PulseDotProps) => { height: "100%", backgroundColor: "inherit", borderRadius: "50%", - animation: "ripple 1.8s ease-out infinite", + animation: `${ripple} 1.8s ease-out infinite`, }, "&::after": { content: `""`, diff --git a/client/src/Pages/Integrations/index.css b/client/src/Pages/Integrations/index.css deleted file mode 100644 index 29969577a..000000000 --- a/client/src/Pages/Integrations/index.css +++ /dev/null @@ -1,10 +0,0 @@ -.integrations h1.MuiTypography-root { - font-size: var(--env-var-font-size-large); - font-weight: 600; -} -.integrations p.MuiTypography-root { - font-size: var(--env-var-font-size-medium); -} -.integrations button { - height: var(--env-var-height-2); -} diff --git a/client/src/Pages/Integrations/index.jsx b/client/src/Pages/Integrations/index.jsx deleted file mode 100644 index dde6b52ee..000000000 --- a/client/src/Pages/Integrations/index.jsx +++ /dev/null @@ -1,156 +0,0 @@ -import PropTypes from "prop-types"; -import { Stack, Typography, Grid, Button } from "@mui/material"; -import { useTheme } from "@emotion/react"; -import Discord from "../../../assets/icons/discord-icon.svg?react"; -import Slack from "../../../assets/icons/slack-icon.svg?react"; -import Zapier from "../../../assets/icons/zapier-icon.svg?react"; -import { useTranslation } from "react-i18next"; - -import "./index.css"; - -/** - * Integrations component - * @param {Object} props - Props for the IntegrationsComponent. - * @param {string} props.icon - The icon for the integration image. - * @param {string} props.header - The header for the integration. - * @param {string} props.info - Information about the integration. - * @param {Function} props.onClick - The onClick handler for the integration button. - * @returns {JSX.Element} The JSX representation of the IntegrationsComponent. - */ -const IntegrationsComponent = ({ icon, header, info, onClick }) => { - const theme = useTheme(); - const { t } = useTranslation(); - - return ( - - - {icon} - - {header} - - {info} - - - - - - ); -}; - -// PropTypes for IntegrationsComponent -IntegrationsComponent.propTypes = { - icon: PropTypes.object.isRequired, - header: PropTypes.string.isRequired, - info: PropTypes.string.isRequired, - onClick: PropTypes.func.isRequired, -}; - -/** - * Integrations Page Component - * @returns {JSX.Element} The JSX representation of the Integrations page. - */ - -const Integrations = () => { - const theme = useTheme(); - const { t } = useTranslation(); - - const integrations = [ - { - icon: ( - - ), - header: t("integrationsSlack"), - info: t("integrationsSlackInfo"), - onClick: () => {}, - }, - { - icon: ( - - ), - header: t("integrationsDiscord"), - info: t("integrationsDiscordInfo"), - onClick: () => {}, - }, - { - icon: ( - - ), - header: t("integrationsZapier"), - info: t("integrationsZapierInfo"), - onClick: () => {}, - }, - // Add more integrations as needed - ]; - - return ( - - {t("integrations")} - {t("integrationsPrism")} - - {integrations.map((integration, index) => ( - - ))} - - - ); -}; - -export default Integrations; diff --git a/client/src/Utils/Theme/globalTheme.js b/client/src/Utils/Theme/globalTheme.js index 37143d730..98f3479be 100644 --- a/client/src/Utils/Theme/globalTheme.js +++ b/client/src/Utils/Theme/globalTheme.js @@ -38,7 +38,6 @@ const baseTheme = (palette) => ({ fontWeight: 400, }, label: { - fontSize: "var(--env-var-font-size-medium)", color: palette.primary.contrastTextSecondary, fontWeight: 500, }, @@ -332,8 +331,6 @@ const baseTheme = (palette) => ({ "& .MuiInputBase-input": { padding: ".75em", - minHeight: "var(--env-var-height-2)", - fontSize: "var(--env-var-font-size-medium)", fontWeight: 400, color: palette.primary.contrastTextSecondary, "&.Mui-disabled": { @@ -368,13 +365,12 @@ const baseTheme = (palette) => ({ "& .MuiFormHelperText-root": { color: palette.error.main, opacity: 0.8, - fontSize: "var(--env-var-font-size-medium)", + fontSize: "var()", marginLeft: 0, }, "& .MuiFormHelperText-root.Mui-error": { opacity: 0.8, - fontSize: "var(--env-var-font-size-medium)", color: palette.error.main, whiteSpace: "nowrap", }, @@ -762,7 +758,6 @@ const baseTheme = (palette) => ({ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", - maxWidth: "calc((100vw - var(--env-var-width-2)) / 2)", }, }, { @@ -775,7 +770,6 @@ const baseTheme = (palette) => ({ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", - maxWidth: "calc((100vw - var(--env-var-width-2)) / 2)", }, }, ], diff --git a/client/src/Utils/Theme/v2Theme.ts b/client/src/Utils/Theme/v2Theme.ts index 57ca76669..39ede6c7e 100644 --- a/client/src/Utils/Theme/v2Theme.ts +++ b/client/src/Utils/Theme/v2Theme.ts @@ -49,6 +49,13 @@ export const theme = (mode: string, palette: any) => }, components: { + MuiTouchRipple: { + styleOverrides: { + root: { + display: "none", + }, + }, + }, MuiButtonBase: { defaultProps: { disableRipple: true, diff --git a/client/src/index.css b/client/src/index.css index 48737d4bb..a662ef475 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -18,70 +18,4 @@ html { text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - - /* Generalized Stylings */ - --env-var-radius-2: 8px; - - --env-var-width-2: 360px; - --env-var-width-4: 100px; - - --env-var-height-2: 34px; - - --env-var-nav-bar-height: 70px; - --env-var-side-bar-width: 250px; - --env-var-side-bar-collapsed-width: 64px; - --env-var-side-bar-auth-footer-height: 50px; - - --env-var-spacing-1: 12px; - --env-var-spacing-1-plus: 16px; - --env-var-spacing-1-minus: 10px; - --env-var-spacing-2: 24px; - - --env-var-font-size-small: 11px; - --env-var-font-size-small-plus: 12px; - --env-var-font-size-medium: 13px; - --env-var-font-size-medium-plus: 14px; - --env-var-font-size-large: 16px; - --env-var-font-size-large-plus: 22px; - --env-var-font-size-xlarge: 30px; -} - -.MuiInputBase-root.Mui-disabled input { - cursor: not-allowed; -} - -/* .Toastify__toast-container { - min-width: 300px; - width: auto; -} -.Toastify__toast-body .alert { - min-width: 150px; - padding: 5px 10px; - align-items: center; -} -.Toastify [class^="Toastify__toast"] { - padding: 0; - margin: 0; -} -.Toastify__toast { - min-height: 0; - border-radius: 4px; -} -.Toastify [class*="Toastify__toast-theme"] { - background-color: transparent; -} */ - -.MuiTouchRipple-root { - display: none; -} - -@keyframes ripple { - from { - opacity: 1; - transform: scale(0); - } - to { - opacity: 0; - transform: scale(2); - } } From f38b305ba703f3606f80d83d240d4b49d3acb319 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 18:07:48 +0000 Subject: [PATCH 16/58] ui slice to TS --- client/src/Features/UI/uiSlice.js | 98 ---------------------- client/src/Features/UI/uiSlice.ts | 133 ++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 98 deletions(-) delete mode 100644 client/src/Features/UI/uiSlice.js create mode 100644 client/src/Features/UI/uiSlice.ts diff --git a/client/src/Features/UI/uiSlice.js b/client/src/Features/UI/uiSlice.js deleted file mode 100644 index 0e8ca8608..000000000 --- a/client/src/Features/UI/uiSlice.js +++ /dev/null @@ -1,98 +0,0 @@ -import { createSlice } from "@reduxjs/toolkit"; - -const initialMode = window?.matchMedia?.("(prefers-color-scheme: dark)")?.matches - ? "dark" - : "light"; - -const initialState = { - monitors: { - rowsPerPage: 10, - }, - team: { - rowsPerPage: 5, - }, - maintenance: { - rowsPerPage: 5, - }, - infrastructure: { - rowsPerPage: 5, - }, - logs: { - rowsPerPage: 15, - }, - sidebar: { - collapsed: false, - }, - mode: initialMode, - showURL: false, - greeting: { index: 0, lastUpdate: null }, - timezone: "America/Toronto", - distributedUptimeEnabled: false, - language: "en", - starPromptOpen: true, - chartType: "histogram", -}; - -const uiSlice = createSlice({ - name: "ui", - initialState, - reducers: { - setDistributedUptimeEnabled: (state, action) => { - state.distributedUptimeEnabled = action.payload; - }, - setRowsPerPage: (state, action) => { - const { table, value } = action.payload; - if (!state[table]) { - state[table] = {}; - } - state[table].rowsPerPage = value; - }, - toggleSidebar: (state) => { - state.sidebar.collapsed = !state.sidebar.collapsed; - }, - setCollapsed: (state, action) => { - const { collapsed } = action.payload; - state.sidebar.collapsed = collapsed; - }, - setMode: (state, action) => { - state.mode = action.payload; - }, - setShowURL: (state, action) => { - state.showURL = action.payload; - }, - setGreeting(state, action) { - if (!state.greeting) { - state.greeting = { index: 0, lastUpdate: null }; - } - state.greeting.index = action.payload.index; - state.greeting.lastUpdate = action.payload.lastUpdate; - }, - setTimezone(state, action) { - state.timezone = action.payload.timezone; - }, - setLanguage: (state, action) => { - state.language = action.payload; - }, - setStarPromptOpen: (state, action) => { - state.starPromptOpen = action.payload; - }, - setChartType: (state, action) => { - state.chartType = action.payload; - }, - }, -}); - -export default uiSlice.reducer; -export const { - setRowsPerPage, - toggleSidebar, - setCollapsed, - setMode, - setShowURL, - setGreeting, - setTimezone, - setDistributedUptimeEnabled, - setLanguage, - setStarPromptOpen, - setChartType, -} = uiSlice.actions; diff --git a/client/src/Features/UI/uiSlice.ts b/client/src/Features/UI/uiSlice.ts new file mode 100644 index 000000000..0675784b9 --- /dev/null +++ b/client/src/Features/UI/uiSlice.ts @@ -0,0 +1,133 @@ +import { createSlice, type PayloadAction } from "@reduxjs/toolkit"; + +type ThemeMode = "light" | "dark"; +type ChartType = "histogram" | "line"; +type TableName = "monitors" | "team" | "maintenance" | "infrastructure" | "logs"; + +interface TableState { + rowsPerPage: number; +} + +interface SidebarState { + collapsed: boolean; +} + +interface GreetingState { + index: number; + lastUpdate: string | null; +} + +interface UIState { + monitors: TableState; + team: TableState; + maintenance: TableState; + infrastructure: TableState; + logs: TableState; + sidebar: SidebarState; + mode: ThemeMode; + showURL: boolean; + greeting: GreetingState; + timezone: string; + distributedUptimeEnabled: boolean; + language: string; + starPromptOpen: boolean; + chartType: ChartType; +} + +const initialMode: ThemeMode = window?.matchMedia?.("(prefers-color-scheme: dark)") + ?.matches + ? "dark" + : "light"; + +const initialState: UIState = { + monitors: { + rowsPerPage: 10, + }, + team: { + rowsPerPage: 5, + }, + maintenance: { + rowsPerPage: 5, + }, + infrastructure: { + rowsPerPage: 5, + }, + logs: { + rowsPerPage: 15, + }, + sidebar: { + collapsed: false, + }, + mode: initialMode, + showURL: false, + greeting: { index: 0, lastUpdate: null }, + timezone: "America/Toronto", + distributedUptimeEnabled: false, + language: "en", + starPromptOpen: true, + chartType: "histogram", +}; + +const uiSlice = createSlice({ + name: "ui", + initialState, + reducers: { + setDistributedUptimeEnabled: (state, action: PayloadAction) => { + state.distributedUptimeEnabled = action.payload; + }, + setRowsPerPage: ( + state, + action: PayloadAction<{ table: TableName; value: number }> + ) => { + const { table, value } = action.payload; + state[table].rowsPerPage = value; + }, + toggleSidebar: (state) => { + state.sidebar.collapsed = !state.sidebar.collapsed; + }, + setCollapsed: (state, action: PayloadAction<{ collapsed: boolean }>) => { + state.sidebar.collapsed = action.payload.collapsed; + }, + setMode: (state, action: PayloadAction) => { + state.mode = action.payload; + }, + setShowURL: (state, action: PayloadAction) => { + state.showURL = action.payload; + }, + setGreeting: ( + state, + action: PayloadAction<{ index: number; lastUpdate: string | null }> + ) => { + state.greeting.index = action.payload.index; + state.greeting.lastUpdate = action.payload.lastUpdate; + }, + setTimezone: (state, action: PayloadAction<{ timezone: string }>) => { + state.timezone = action.payload.timezone; + }, + setLanguage: (state, action: PayloadAction) => { + state.language = action.payload; + }, + setStarPromptOpen: (state, action: PayloadAction) => { + state.starPromptOpen = action.payload; + }, + setChartType: (state, action: PayloadAction) => { + state.chartType = action.payload; + }, + }, +}); + +export type { UIState, ThemeMode, ChartType, TableName }; +export default uiSlice.reducer; +export const { + setRowsPerPage, + toggleSidebar, + setCollapsed, + setMode, + setShowURL, + setGreeting, + setTimezone, + setDistributedUptimeEnabled, + setLanguage, + setStarPromptOpen, + setChartType, +} = uiSlice.actions; From 85dbe34e009e0b796635b07b8bd747b46ecce24e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 18:30:15 +0000 Subject: [PATCH 17/58] store to ts --- client/src/main.tsx | 2 +- client/src/{store.js => store.ts} | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) rename client/src/{store.js => store.ts} (59%) diff --git a/client/src/main.tsx b/client/src/main.tsx index 813a839bd..1e339f87b 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -3,7 +3,7 @@ import App from "./App.jsx"; import "./index.css"; import { BrowserRouter as Router } from "react-router-dom"; import { Provider } from "react-redux"; -import { persistor, store } from "./store.js"; +import { persistor, store } from "@/store.js"; import { PersistGate } from "redux-persist/integration/react"; import I18nLoader from "./Components/v1/I18nLoader/index.jsx"; import { initApiClient } from "./Utils/ApiClient.js"; diff --git a/client/src/store.js b/client/src/store.ts similarity index 59% rename from client/src/store.js rename to client/src/store.ts index 69aa3d50b..9e064b55f 100644 --- a/client/src/store.js +++ b/client/src/store.ts @@ -1,18 +1,21 @@ import { configureStore, combineReducers } from "@reduxjs/toolkit"; - -import authReducer from "./Features/Auth/authSlice"; -import uiReducer from "./Features/UI/uiSlice"; +import authReducer from "@/Features/Auth/authSlice"; +import uiReducer from "@/Features/UI/uiSlice"; import storage from "redux-persist/lib/storage"; -import { persistReducer, persistStore, createTransform } from "redux-persist"; +import { + persistReducer, + persistStore, + createTransform, + PERSIST, + REHYDRATE, +} from "redux-persist"; const authTransform = createTransform( - (inboundState) => { + (inboundState: Record) => { const { profileImage, ...rest } = inboundState; return rest; }, - // No transformation on rehydration - null, - // Only applies to auth + undefined, { whitelist: ["auth"] } ); @@ -28,6 +31,7 @@ const rootReducer = combineReducers({ ui: uiReducer, }); +// @ts-expect-error - redux-persist types don't align perfectly with redux-toolkit const persistedReducer = persistReducer(persistConfig, rootReducer); export const store = configureStore({ @@ -35,10 +39,13 @@ export const store = configureStore({ middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { - ignoredActions: ["persist/PERSIST", "persist/REHYDRATE", "persist/REGISTER"], + ignoredActions: [PERSIST, REHYDRATE, "persist/REGISTER"], }, }), }); +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; + export const persistor = persistStore(store); export default store; From b0b7b6a435a9bce516e51ae0d475dfa9bc3164d4 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 18:30:44 +0000 Subject: [PATCH 18/58] fix status change issue --- .../SuperSimpleQueue/SuperSimpleQueueHelper.ts | 1 - server/src/service/infrastructure/statusService.ts | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index d5d275e59..6cd1a7675 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -89,7 +89,6 @@ class SuperSimpleQueueHelper { // Step 4 Add check to buffer this.buffer.addToBuffer({ check }); - // Step 4. Update monitor status const statusChangeResult = await this.statusService.updateMonitorStatus(status, check); diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index 506ad5396..284fd3ff7 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -3,6 +3,7 @@ import MonitorStats from "../../db/models/MonitorStats.js"; import { CheckModel } from "@/db/models/index.js"; import type { Monitor, + MonitorStatus, MonitorStatusResponse, StatusChangeResult, Check, @@ -200,14 +201,13 @@ export class StatusService implements IStatusService { monitor.recentChecks.shift(); } - monitor.status = status === true ? "up" : "down"; - const prevStatus = monitor.status; - let newStatus = monitor.status; + let newStatus: MonitorStatus = status === true ? "up" : "down"; let statusChanged = false; // Return early if not enough data points if (monitor.statusWindow.length < monitor.statusWindowSize) { + monitor.status = newStatus; const updated = await this.monitorsRepository.updateById(monitor.id, monitor.teamId, monitor); return { monitor: updated, From cafea2bf5dd058770e80891d3181f3fe5cd34c78 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 19:13:53 +0000 Subject: [PATCH 19/58] remove unused utils, convert utils to TS --- client/src/App.tsx | 8 - .../index.jsx => v2/i18nLoader/index.tsx} | 5 +- .../v2/monitors/charts/HistogramStatus.tsx | 2 +- client/src/Features/UI/uiSlice.ts | 16 +- .../Incidents/Components/IncidentTable.tsx | 4 +- client/src/Utils/Logger.js | 74 ------- client/src/Utils/MonitorUtils.ts | 8 +- client/src/Utils/ReadMe.md | 1 - client/src/Utils/fileUtils.js | 11 - client/src/Utils/greeting.jsx | 197 ------------------ client/src/Utils/{i18n.js => i18n.ts} | 20 +- client/src/Utils/monitorUtilsLegacy.js | 47 ----- client/src/Utils/roleUtils.js | 13 -- client/src/Utils/stringUtils.js | 46 ---- client/src/Utils/timeUtilsLegacy.js | 167 --------------- client/src/Utils/utils.js | 15 -- client/src/Validation/error.js | 101 --------- client/src/Validation/validation.js | 14 +- client/src/main.tsx | 2 +- 19 files changed, 40 insertions(+), 711 deletions(-) rename client/src/Components/{v1/I18nLoader/index.jsx => v2/i18nLoader/index.tsx} (63%) delete mode 100644 client/src/Utils/Logger.js delete mode 100644 client/src/Utils/ReadMe.md delete mode 100644 client/src/Utils/fileUtils.js delete mode 100644 client/src/Utils/greeting.jsx rename client/src/Utils/{i18n.js => i18n.ts} (55%) delete mode 100644 client/src/Utils/monitorUtilsLegacy.js delete mode 100644 client/src/Utils/roleUtils.js delete mode 100644 client/src/Utils/stringUtils.js delete mode 100644 client/src/Utils/timeUtilsLegacy.js delete mode 100644 client/src/Utils/utils.js delete mode 100644 client/src/Validation/error.js diff --git a/client/src/App.tsx b/client/src/App.tsx index 0a6b364f8..1004131e3 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -6,7 +6,6 @@ import { ThemeProvider } from "@emotion/react"; import lightTheme from "./Utils/Theme/lightTheme"; import darkTheme from "./Utils/Theme/darkTheme"; import { CssBaseline, GlobalStyles } from "@mui/material"; -import { logger } from "./Utils/Logger"; // Import the logger import { Routes } from "./Routes"; import AppLayout from "@/Components/v2/layout/AppLayout"; import type { RootState } from "@/Types/state"; @@ -14,13 +13,6 @@ import type { RootState } from "@/Types/state"; function App() { const mode = useSelector((state: RootState) => state.ui.mode); - // Cleanup - useEffect(() => { - return () => { - logger.cleanup(); - }; - }, []); - const theme = mode === "light" ? lightTheme : darkTheme; return ( diff --git a/client/src/Components/v1/I18nLoader/index.jsx b/client/src/Components/v2/i18nLoader/index.tsx similarity index 63% rename from client/src/Components/v1/I18nLoader/index.jsx rename to client/src/Components/v2/i18nLoader/index.tsx index 676e63d7b..f0555afed 100644 --- a/client/src/Components/v1/I18nLoader/index.jsx +++ b/client/src/Components/v2/i18nLoader/index.tsx @@ -1,8 +1,9 @@ -import i18n from "../../../Utils/i18n.js"; +import i18n from "@/Utils/i18n.js"; import { useSelector } from "react-redux"; import { useEffect } from "react"; +import type { RootState } from "@/store"; const I18nLoader = () => { - const language = useSelector((state) => state.ui.language ?? "en"); + const language = useSelector((state: RootState) => state.ui.language ?? "en"); useEffect(() => { if (language && i18n.language !== language) { diff --git a/client/src/Components/v2/monitors/charts/HistogramStatus.tsx b/client/src/Components/v2/monitors/charts/HistogramStatus.tsx index 1c25c339e..d3aa62a69 100644 --- a/client/src/Components/v2/monitors/charts/HistogramStatus.tsx +++ b/client/src/Components/v2/monitors/charts/HistogramStatus.tsx @@ -3,7 +3,7 @@ import Typography from "@mui/material/Typography"; import { BaseChart } from "@/Components/v2/design-elements"; import { useTheme } from "@mui/material/styles"; import { useSelector } from "react-redux"; -import { formatDateWithTz } from "@/Utils/timeUtilsLegacy"; +import { formatDateWithTz } from "@/Utils/TimeUtils"; import { useTranslation } from "react-i18next"; import { ResponsiveContainer, BarChart, XAxis, Bar, Cell, Tooltip } from "recharts"; import { getResponseTimeColor } from "@/Utils/MonitorUtils"; diff --git a/client/src/Features/UI/uiSlice.ts b/client/src/Features/UI/uiSlice.ts index 0675784b9..84e8248db 100644 --- a/client/src/Features/UI/uiSlice.ts +++ b/client/src/Features/UI/uiSlice.ts @@ -12,11 +12,6 @@ interface SidebarState { collapsed: boolean; } -interface GreetingState { - index: number; - lastUpdate: string | null; -} - interface UIState { monitors: TableState; team: TableState; @@ -26,7 +21,6 @@ interface UIState { sidebar: SidebarState; mode: ThemeMode; showURL: boolean; - greeting: GreetingState; timezone: string; distributedUptimeEnabled: boolean; language: string; @@ -60,7 +54,6 @@ const initialState: UIState = { }, mode: initialMode, showURL: false, - greeting: { index: 0, lastUpdate: null }, timezone: "America/Toronto", distributedUptimeEnabled: false, language: "en", @@ -94,13 +87,7 @@ const uiSlice = createSlice({ setShowURL: (state, action: PayloadAction) => { state.showURL = action.payload; }, - setGreeting: ( - state, - action: PayloadAction<{ index: number; lastUpdate: string | null }> - ) => { - state.greeting.index = action.payload.index; - state.greeting.lastUpdate = action.payload.lastUpdate; - }, + setTimezone: (state, action: PayloadAction<{ timezone: string }>) => { state.timezone = action.payload.timezone; }, @@ -124,7 +111,6 @@ export const { setCollapsed, setMode, setShowURL, - setGreeting, setTimezone, setDistributedUptimeEnabled, setLanguage, diff --git a/client/src/Pages/Incidents/Components/IncidentTable.tsx b/client/src/Pages/Incidents/Components/IncidentTable.tsx index 121f33123..a9b4bc104 100644 --- a/client/src/Pages/Incidents/Components/IncidentTable.tsx +++ b/client/src/Pages/Incidents/Components/IncidentTable.tsx @@ -9,13 +9,13 @@ import type { Monitor } from "@/Types/Monitor"; import type { ActionMenuItem } from "@/Components/v2/actions-menu"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; -import { TypeToPathMap } from "@/Utils/monitorUtilsLegacy.js"; import { formatDateWithTz } from "@/Utils/TimeUtils"; import { useSelector } from "react-redux"; import type { RootState } from "@/Types/state"; import Typography from "@mui/material/Typography"; import { useTheme } from "@mui/material/styles"; import Box from "@mui/material/Box"; +import { getMonitorPath } from "@/Utils/MonitorUtils"; interface IncidentsTableProps { title?: string; @@ -62,7 +62,7 @@ export const IncidentsTable = ({ label: t("pages.incidents.table.actions.goToMonitor"), action: () => { if (monitor) { - const path = TypeToPathMap[monitor.type as keyof typeof TypeToPathMap]; + const path = getMonitorPath(monitor.type); if (path && monitor.id) { navigate(`/${path}/${monitor.id}`); } diff --git a/client/src/Utils/Logger.js b/client/src/Utils/Logger.js deleted file mode 100644 index 849e10854..000000000 --- a/client/src/Utils/Logger.js +++ /dev/null @@ -1,74 +0,0 @@ -const LOG_LEVEL = import.meta.env.VITE_APP_LOG_LEVEL || "debug"; -const NO_OP = () => {}; - -class Logger { - constructor() { - let logLevel = LOG_LEVEL; - this.updateLogLevel(logLevel); - // Defer store subscription to avoid circular dependency during HMR - setTimeout(() => { - try { - import("../store").then(({ default: store }) => { - if (store) { - this.unsubscribe = store.subscribe(() => { - logLevel = "debug"; - this.updateLogLevel(logLevel); - }); - } - }); - } catch (e) { - // Store not ready yet, ignore - } - }, 0); - } - - updateLogLevel(logLevel) { - if (logLevel === "none") { - this.info = NO_OP; - this.error = NO_OP; - this.warn = NO_OP; - this.log = NO_OP; - return; - } - - if (logLevel === "error") { - this.error = console.error.bind(console); - this.info = NO_OP; - this.warn = NO_OP; - this.log = NO_OP; - return; - } - - if (logLevel === "warn") { - this.error = console.error.bind(console); - this.warn = console.warn.bind(console); - this.info = NO_OP; - this.log = NO_OP; - return; - } - - if (logLevel === "info") { - this.error = console.error.bind(console); - this.warn = console.warn.bind(console); - this.info = console.info.bind(console); - this.log = NO_OP; - return; - } - - if (logLevel === "debug") { - this.error = console.error.bind(console); - this.warn = console.warn.bind(console); - this.info = console.info.bind(console); - this.log = console.log.bind(console); - return; - } - } - - cleanup() { - if (this.unsubscribe) { - this.unsubscribe(); - } - } -} - -export const logger = new Logger(); diff --git a/client/src/Utils/MonitorUtils.ts b/client/src/Utils/MonitorUtils.ts index 703579fc6..7d7149c9d 100644 --- a/client/src/Utils/MonitorUtils.ts +++ b/client/src/Utils/MonitorUtils.ts @@ -7,11 +7,11 @@ export const getMonitorPath = (type: MonitorType): string => { http: "uptime", port: "uptime", ping: "uptime", - hardware: "hardware", - pagespeed: "pagespeed", - docker: "docker", - game: "game-servers", + game: "uptime", unknown: "uptime", + docker: "uptime", + hardware: "infrastructure", + pagespeed: "pagespeed", }; return pathMap[type]; }; diff --git a/client/src/Utils/ReadMe.md b/client/src/Utils/ReadMe.md deleted file mode 100644 index 6488752d1..000000000 --- a/client/src/Utils/ReadMe.md +++ /dev/null @@ -1 +0,0 @@ -#Utils folder diff --git a/client/src/Utils/fileUtils.js b/client/src/Utils/fileUtils.js deleted file mode 100644 index 1c35738dd..000000000 --- a/client/src/Utils/fileUtils.js +++ /dev/null @@ -1,11 +0,0 @@ -export const formatBytes = (bytes) => { - if (bytes === 0) return "0 Bytes"; - const megabytes = bytes / (1024 * 1024); - return megabytes.toFixed(2) + " MB"; -}; - -export const checkImage = (url) => { - const img = new Image(); - img.src = url; - return img.naturalWidth !== 0; -}; diff --git a/client/src/Utils/greeting.jsx b/client/src/Utils/greeting.jsx deleted file mode 100644 index c4afbf88c..000000000 --- a/client/src/Utils/greeting.jsx +++ /dev/null @@ -1,197 +0,0 @@ -import PropTypes from "prop-types"; -import { useTheme } from "@emotion/react"; -import { Box, Typography } from "@mui/material"; -import { useDispatch, useSelector } from "react-redux"; -import { useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { setGreeting } from "../Features/UI/uiSlice"; - -const early = [ - { - prepend: "Rise and shine", - append: "If you’re up this early, you might as well be a legend!", - emoji: "☕", - }, - { - prepend: "Good morning", - append: "The world’s still asleep, but you’re already awesome!", - emoji: "🦉", - }, - { - prepend: "Good morning", - append: "Are you a wizard? Only magical people are up at this hour!", - emoji: "🌄", - }, - { - prepend: "Up before the roosters", - append: "Ready to tackle the day before it even starts?", - emoji: "🐓", - }, - { - prepend: "Early bird special", - append: "Let’s get things done while everyone else is snoozing!", - emoji: "🌟", - }, -]; - -const morning = [ - { - prepend: "Good morning", - append: "Is it coffee o’clock yet, or should we start with high fives?", - emoji: "☕", - }, - { - prepend: "Morning", - append: "The sun is up, and so are you—time to be amazing!", - emoji: "🌞", - }, - { - prepend: "Good morning", - append: "Time to make today the best thing since sliced bread!", - emoji: "🥐", - }, - { - prepend: "Morning", - append: "Let’s kick off the day with more energy than a double espresso!", - emoji: "🚀", - }, - { - prepend: "Rise and shine", - append: "You’re about to make today so great, even Monday will be jealous!", - emoji: "🌟", - }, -]; - -const afternoon = [ - { - prepend: "Good afternoon", - append: "How about a break to celebrate how awesome you’re doing?", - emoji: "🥪", - }, - { - prepend: "Afternoon", - append: "If you’re still going strong, you’re officially a rockstar!", - emoji: "🌞", - }, - { - prepend: "Hey there", - append: "The afternoon is your playground—let’s make it epic!", - emoji: "🍕", - }, - { - prepend: "Good afternoon", - append: "Time to crush the rest of the day like a pro!", - emoji: "🏆", - }, - { - prepend: "Afternoon", - append: "Time to turn those afternoon slumps into afternoon triumphs!", - emoji: "🎉", - }, -]; - -const evening = [ - { - prepend: "Good evening", - append: "Time to wind down and think about how you crushed today!", - emoji: "🌇", - }, - { - prepend: "Evening", - append: "You’ve earned a break—let’s make the most of these evening vibes!", - emoji: "🍹", - }, - { - prepend: "Hey there", - append: "Time to relax and bask in the glow of your day’s awesomeness!", - emoji: "🌙", - }, - { - prepend: "Good evening", - append: "Ready to trade productivity for chill mode?", - emoji: "🛋️ ", - }, - { - prepend: "Evening", - append: "Let’s call it a day and toast to your success!", - emoji: "🕶️", - }, -]; - -/** - * Greeting component that displays a personalized greeting message - * based on the time of day and the user's first name. - * - * @component - * @example - * return ; - * - * @param {Object} props - * @param {string} props.type - The type of monitor to be displayed in the message - * @returns {JSX.Element} The rendered Greeting component - */ - -const Greeting = ({ type = "" }) => { - const theme = useTheme(); - const dispatch = useDispatch(); - const { t } = useTranslation(); - const { firstName } = useSelector((state) => state.auth.user); - const index = useSelector((state) => state.ui.greeting?.index ?? 0); - const lastUpdate = useSelector((state) => state.ui.greeting?.lastUpdate ?? null); - - const now = new Date(); - const hour = now.getHours(); - - useEffect(() => { - const hourDiff = lastUpdate ? hour - lastUpdate : null; - - if (!lastUpdate || hourDiff >= 1) { - let random = Math.floor(Math.random() * 5); - dispatch(setGreeting({ index: random, lastUpdate: hour })); - } - }, [dispatch, hour, lastUpdate]); - - let greetingArray = - hour < 6 ? early : hour < 12 ? morning : hour < 18 ? afternoon : evening; - const { prepend, append, emoji } = greetingArray[index]; - - return ( - - - - {t("greeting.prepend", { defaultValue: prepend })},{" "} - - - {firstName} {emoji} - - - - {t("greeting.append", { defaultValue: append })} —{" "} - {t("greeting.overview", { type: t(`menu.${type}`) })} - - - ); -}; - -Greeting.propTypes = { - type: PropTypes.string, -}; - -export default Greeting; diff --git a/client/src/Utils/i18n.js b/client/src/Utils/i18n.ts similarity index 55% rename from client/src/Utils/i18n.js rename to client/src/Utils/i18n.ts index 030091d48..db448a065 100644 --- a/client/src/Utils/i18n.js +++ b/client/src/Utils/i18n.ts @@ -1,16 +1,26 @@ import i18n from "i18next"; import { initReactI18next } from "react-i18next"; +import type { Resource } from "i18next"; const primaryLanguage = "en"; -// Load all translation files eagerly -const translations = import.meta.glob("../locales/*.json", { eager: true }); +interface TranslationModule { + default?: Record; + [key: string]: unknown; +} -const resources = {}; +// Load all translation files eagerly +const translations = import.meta.glob("../locales/*.json", { + eager: true, +}); + +const resources: Resource = {}; Object.keys(translations).forEach((path) => { - const langCode = path.match(/\/([^/]+)\.json$/)[1]; + const match = path.match(/\/([^/]+)\.json$/); + if (!match) return; + const langCode = match[1]; resources[langCode] = { - translation: translations[path].default || translations[path], + translation: translations[path].default ?? translations[path], }; }); diff --git a/client/src/Utils/monitorUtilsLegacy.js b/client/src/Utils/monitorUtilsLegacy.js deleted file mode 100644 index e3645b0d0..000000000 --- a/client/src/Utils/monitorUtilsLegacy.js +++ /dev/null @@ -1,47 +0,0 @@ -import { capitalizeFirstLetter } from "./stringUtils"; - -/** - * Helper function to get duration since last check or the last date checked - * @param {Array} checks Array of check objects. - * @param {boolean} duration Whether the function should return the duration since last checked or the date itself - * @returns {number} Timestamp of the most recent check. - */ -export const getLastChecked = (checks, duration = true) => { - if (!checks || checks.length === 0) { - return 0; // Handle case when no checks are available - } - - // Data is sorted newest -> oldest, so newest check is the most recent - if (!duration) { - return new Date(checks[0].createdAt); - } - return new Date() - new Date(checks[0].createdAt); -}; - -export const parseDomainName = (url) => { - url = url.replace(/^https?:\/\//, ""); - // Remove leading/trailing dots - url = url.replace(/^\.+|\.+$/g, ""); - // Split by dots - const parts = url.split("."); - // Remove common prefixes and empty parts and exclude the last element of the array (the last element should be the TLD) - const cleanParts = parts.filter((part) => part !== "www" && part !== "").slice(0, -1); - // If there's more than one part, append the two words and capitalize the first letters (e.g. ["api", "test"] -> "Api Test") - const domainPart = - cleanParts.length > 1 - ? cleanParts.map((part) => capitalizeFirstLetter(part)).join(" ") - : capitalizeFirstLetter(cleanParts[0]); - - if (domainPart) return domainPart; - - return url; -}; - -export const TypeToPathMap = { - http: "uptime", - port: "uptime", - docker: "uptime", - ping: "uptime", - hardware: "infrastructure", - pagespeed: "pagespeed", -}; diff --git a/client/src/Utils/roleUtils.js b/client/src/Utils/roleUtils.js deleted file mode 100644 index f359246b2..000000000 --- a/client/src/Utils/roleUtils.js +++ /dev/null @@ -1,13 +0,0 @@ -export const ROLES = { - SUPERADMIN: "superadmin", - ADMIN: "admin", - USER: "user", - DEMO: "demo", -}; - -export const VALID_ROLES = [ROLES.ADMIN, ROLES.USER, ROLES.DEMO]; - -export const EDITABLE_ROLES = [ - { role: ROLES.ADMIN, _id: ROLES.ADMIN }, - { role: ROLES.USER, _id: ROLES.USER }, -]; diff --git a/client/src/Utils/stringUtils.js b/client/src/Utils/stringUtils.js deleted file mode 100644 index bb62d0169..000000000 --- a/client/src/Utils/stringUtils.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Helper function to get first letter capitalized string - * @param {string} str String whose first letter is to be capitalized - * @returns A string with first letter capitalized - */ -export const capitalizeFirstLetter = (str) => { - if (str === null || str === undefined) { - return ""; - } - if (typeof str !== "string") { - throw new TypeError("Input must be a string"); - } - if (str.length === 0) { - return ""; - } - return str.charAt(0).toUpperCase() + str.slice(1); -}; - -/** - * Helper function to get first letter as a lower case string - * @param {string} str String whose first letter is to be lower cased - * @returns A string with first letter lower cased - */ - -export const toLowerCaseFirstLetter = (str) => { - if (str === null || str === undefined) { - return ""; - } - if (typeof str !== "string") { - throw new TypeError("Input must be a string"); - } - if (str.length === 0) { - return ""; - } - return str.charAt(0).toLowerCase() + str.slice(1); -}; - -/** - * Checks if a string is null, undefined, or empty (including strings with only whitespace). - * @param {string} str - The string to check. - * @returns {boolean} - Returns true if the string is null, undefined, or empty. - */ -export const isEmpty = (str) => { - // Check if string is null, undefined, or empty (including whitespace only) - return str === null || typeof str === "undefined" || str.trim().length === 0; -}; diff --git a/client/src/Utils/timeUtilsLegacy.js b/client/src/Utils/timeUtilsLegacy.js deleted file mode 100644 index 365572f6b..000000000 --- a/client/src/Utils/timeUtilsLegacy.js +++ /dev/null @@ -1,167 +0,0 @@ -import dayjs from "dayjs"; -import duration from "dayjs/plugin/duration"; -import utc from "dayjs/plugin/utc"; -import timezone from "dayjs/plugin/timezone"; -import customParseFormat from "dayjs/plugin/customParseFormat"; - -dayjs.extend(utc); -dayjs.extend(timezone); -dayjs.extend(customParseFormat); -dayjs.extend(duration); - -export const MS_PER_SECOND = 1000; -export const MS_PER_MINUTE = 60 * MS_PER_SECOND; -export const MS_PER_HOUR = 60 * MS_PER_MINUTE; -export const MS_PER_DAY = 24 * MS_PER_HOUR; -export const MS_PER_WEEK = MS_PER_DAY * 7; - -export const formatDuration = (ms) => { - const seconds = Math.floor(ms / 1000); - const minutes = Math.floor(seconds / 60); - const hours = Math.floor(minutes / 60); - const days = Math.floor(hours / 24); - - let dateStr = ""; - - days && (dateStr += `${days}d `); - hours && (dateStr += `${hours % 24}h `); - minutes && (dateStr += `${minutes % 60}m `); - seconds && (dateStr += `${seconds % 60}s `); - - dateStr === "" && (dateStr = "0s"); - - return dateStr; -}; - -export const formatDurationRounded = (ms) => { - const seconds = Math.floor(ms / 1000); - const minutes = Math.floor(seconds / 60); - const hours = Math.floor(minutes / 60); - const days = Math.floor(hours / 24); - - let time = ""; - if (days > 0) { - time += `${days} day${days !== 1 ? "s" : ""}`; - return time; - } - if (hours > 0) { - time += `${hours} hour${hours !== 1 ? "s" : ""}`; - return time; - } - if (minutes > 0) { - time += `${minutes} minute${minutes !== 1 ? "s" : ""}`; - return time; - } - if (seconds > 0) { - time += `${seconds} second${seconds !== 1 ? "s" : ""}`; - return time; - } - - return time; -}; - -export const formatDurationSplit = (ms) => { - const seconds = Math.floor(ms / 1000); - const minutes = Math.floor(seconds / 60); - const hours = Math.floor(minutes / 60); - const days = Math.floor(hours / 24); - - return days > 0 - ? { time: days, format: days === 1 ? "day" : "days" } - : hours > 0 - ? { time: hours, format: hours === 1 ? "hour" : "hours" } - : minutes > 0 - ? { time: minutes, format: minutes === 1 ? "minute" : "minutes" } - : seconds > 0 - ? { time: seconds, format: seconds === 1 ? "second" : "seconds" } - : { time: 0, format: "seconds" }; -}; - -export const getHumanReadableDuration = (ms) => { - const durationObj = dayjs.duration(ms); - - const parts = { - days: Math.floor(durationObj.asDays()), - hours: durationObj.hours(), - minutes: durationObj.minutes(), - seconds: durationObj.seconds(), - milliseconds: durationObj.milliseconds(), - }; - - const result = []; - - if (parts.days > 0) { - result.push(`${parts.days}d`); - } - if (parts.hours > 0) { - result.push(`${parts.hours}h`); - } - if (result.length < 2 && parts.minutes > 0) { - result.push(`${parts.minutes}m`); - } - if (result.length < 2 && parts.seconds > 0) { - result.push(`${parts.seconds}s`); - } - if (result.length < 2 && parts.milliseconds > 0 && parts.seconds < 1) { - result.push(`${parts.milliseconds.toFixed(2)}ms`); - } - - if (result.length === 0) { - // fallback for durations < 1s - return "0s"; - } - - return result.join(" "); -}; - -export const formatDate = (date, customOptions) => { - const options = { - year: "numeric", - month: "long", - day: "numeric", - hour: "numeric", - minute: "numeric", - hour12: true, - ...customOptions, - }; - - // Return the date using the specified options - return date - .toLocaleString("en-US", options) - .replace(/\b(AM|PM)\b/g, (match) => match.toLowerCase()); -}; - -export const formatDateWithTz = (timestamp, format, timezone) => { - const formattedDate = dayjs(timestamp).tz(timezone).format(format); - return formattedDate; -}; - -export const tickDateFormatLookup = (range) => { - switch (range) { - case "recent": - return "h:mm A"; - case "day": - return "h A"; - case "week": - return "MMM D"; - case "month": - return "MMM D"; - default: - return "MMM D, h A"; - } -}; - -export const tooltipDateFormatLookup = (range) => { - switch (range) { - case "recent": - return "MMM D, h:mm A"; - case "day": - return "MMM D, h:mm A"; - case "week": - return "ddd, MMM D"; - case "month": - return "ddd, MMM D"; - default: - return "MMM D, h:mm A"; - } -}; diff --git a/client/src/Utils/utils.js b/client/src/Utils/utils.js deleted file mode 100644 index 81ec44b06..000000000 --- a/client/src/Utils/utils.js +++ /dev/null @@ -1,15 +0,0 @@ -export const safelyParseFloat = (value) => { - const parsedValue = parseFloat(value); - if (isNaN(parsedValue)) { - return 0; - } - return parsedValue; -}; - -export const formatMonitorUrl = (url, maxLength = 55) => { - if (!url) return ""; - const strippedUrl = url.replace(/^https?:\/\//, ""); - return strippedUrl.length > maxLength - ? `${strippedUrl.slice(0, maxLength)}…` - : strippedUrl; -}; diff --git a/client/src/Validation/error.js b/client/src/Validation/error.js deleted file mode 100644 index 5738edf40..000000000 --- a/client/src/Validation/error.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Update errors if passed id matches the error.details[0].path, otherwise remove - * the error for the id - * @param {*} prev Previous errors * - * @param {*} id ID of the field whose error is to be either updated or removed - * @param {*} error the error object - * @returns the Update Errors with the specific field with id being either removed or updated - */ - -const buildErrors = (prev, id, error) => { - const updatedErrors = { ...prev }; - if (error && id == error.details[0].path) { - updatedErrors[id] = error.details[0].message ?? "Validation error"; - } else { - delete updatedErrors[id]; - } - return updatedErrors; -}; - -/** - * Processes Joi validation errors and returns a filtered object of error messages for fields that have been touched. - * - * @param {Object} validation - The Joi validation result object. - * @param {Object} validation.error - The error property of the validation result containing details of validation failures. - * @param {Object[]} validation.error.details - An array of error details from the Joi validation. Each item contains information about the path and the message. - * @param {Object} touchedErrors - An object representing which fields have been interacted with. Keys are field IDs (field names), and values are booleans indicating whether the field has been touched. - * @returns {Object} - An object where keys are the field IDs (if they exist in `touchedErrors` and are in the error details) and values are their corresponding error messages. - */ -const getTouchedFieldErrors = (validation, touchedErrors) => { - let newErrors = {}; - - if (validation?.error) { - newErrors = validation.error.details.reduce((errors, detail) => { - const fieldId = detail.path[0]; - if (touchedErrors[fieldId] && !(fieldId in errors)) { - errors[fieldId] = detail.message; - } - return errors; - }, {}); - } - - return newErrors; -}; -/** - * - * @param {*} form The form object of the submitted form data - * @param {*} validation The Joi validation rules - * @param {*} setErrors The function used to set the local errors - * @returns true if there is no error or false if there is error after validating the form - * the error will be reset to {} if returns false; otherwise the errors object will be set with - * the new value - */ -const hasValidationErrors = (form, validation, setErrors) => { - const { error } = validation.validate(form, { - abortEarly: false, - }); - if (error) { - const newErrors = {}; - error.details.forEach((err) => { - if ( - ![ - "clientHost", - "refreshTokenSecret", - "dbConnectionString", - "refreshTokenTTL", - "jwtTTL", - "notify-email-list", - "_id", - "__v", - "createdAt", - "updatedAt", - ].includes(err.path[0]) - ) { - newErrors[err.path[0]] = err.message ?? "Validation error"; - } - // Handle conditionally usage number required cases - if (!form.cpu || form.usage_cpu) { - newErrors["usage_cpu"] = null; - } - if (!form.memory || form.usage_memory) { - newErrors["usage_memory"] = null; - } - if (!form.disk || form.usage_disk) { - newErrors["usage_disk"] = null; - } - if (!form.temperature || form.usage_temperature) { - newErrors["usage_temperature"] = null; - } - }); - if (Object.values(newErrors).some((v) => v)) { - setErrors(newErrors); - return true; - } else { - setErrors({}); - return false; - } - } - setErrors({}); - return false; -}; -export { buildErrors, hasValidationErrors, getTouchedFieldErrors }; diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 27d585074..fa92f2e99 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -1,6 +1,18 @@ import joi from "joi"; import dayjs from "dayjs"; -import { ROLES } from "../Utils/roleUtils"; +export const ROLES = { + SUPERADMIN: "superadmin", + ADMIN: "admin", + USER: "user", + DEMO: "demo", +}; + +export const VALID_ROLES = [ROLES.ADMIN, ROLES.USER, ROLES.DEMO]; + +export const EDITABLE_ROLES = [ + { role: ROLES.ADMIN, _id: ROLES.ADMIN }, + { role: ROLES.USER, _id: ROLES.USER }, +]; const THRESHOLD_COMMON_BASE_MSG = "Threshold must be a number."; diff --git a/client/src/main.tsx b/client/src/main.tsx index 1e339f87b..f075886d3 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -5,7 +5,7 @@ import { BrowserRouter as Router } from "react-router-dom"; import { Provider } from "react-redux"; import { persistor, store } from "@/store.js"; import { PersistGate } from "redux-persist/integration/react"; -import I18nLoader from "./Components/v1/I18nLoader/index.jsx"; +import I18nLoader from "./Components/v2/i18nLoader"; import { initApiClient } from "./Utils/ApiClient.js"; initApiClient(store); From f600647ff0f693f79023c1298424c6f8192eeb09 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 19:16:16 +0000 Subject: [PATCH 20/58] fix ts error --- client/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 1004131e3..a8a25669e 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,4 +1,4 @@ -import { useEffect, type CSSProperties } from "react"; +import { type CSSProperties } from "react"; import { useSelector } from "react-redux"; import "react-toastify/dist/ReactToastify.css"; import { ToastContainer } from "react-toastify"; From 8089e71f96c41fb0b5029fdcc8cb420881c721e1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 19:42:58 +0000 Subject: [PATCH 21/58] warn instead of throw on failure to build check --- .../SuperSimpleQueue/SuperSimpleQueueHelper.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 6cd1a7675..6c9e9264a 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -86,7 +86,15 @@ class SuperSimpleQueueHelper { // Step 3. Build check const check = await this.checkService.buildCheck(status); - + if (!check) { + this.logger.warn({ + message: `No check could be built for monitor ${monitorId}`, + service: SERVICE_NAME, + method: "getMonitorJob", + details: { code: status.code, message: status.message }, + }); + return; + } // Step 4 Add check to buffer this.buffer.addToBuffer({ check }); // Step 4. Update monitor status From f337ca5ff04c7c281d3e0a58883778812bdb89f6 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 22:37:40 +0000 Subject: [PATCH 22/58] initial commit --- server/src/config/controllers.ts | 2 +- server/src/config/services.ts | 14 +--------- server/src/controllers/settingsController.ts | 4 +-- .../monitor-stats/IMonitorStatsRepository.ts | 1 + .../MongoMonitorStatsRepository.ts | 5 ++++ .../service/infrastructure/bufferService.ts | 12 ++++++--- .../service/infrastructure/statusService.ts | 27 ++++++++++++------- 7 files changed, 36 insertions(+), 29 deletions(-) diff --git a/server/src/config/controllers.ts b/server/src/config/controllers.ts index 7a20ed93c..8a83a0f63 100644 --- a/server/src/config/controllers.ts +++ b/server/src/config/controllers.ts @@ -30,7 +30,7 @@ export const initializeControllers = (services: InitializedServices): Initialize return { authController: new AuthController(services.userService), monitorController: new MonitorController(services.monitorService), - settingsController: new SettingsController(services.settingsService, services.emailService, services.db), + settingsController: new SettingsController(services.settingsService, services.emailService), checkController: new CheckController(services.checkService), inviteController: new InviteController(services.inviteService), maintenanceWindowController: new MaintenanceWindowController(services.maintenanceWindowService), diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 9bf18ff1d..f88bc2584 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -41,18 +41,6 @@ import crypto from "crypto"; import { games, GameDig } from "gamedig"; import jmespath from "jmespath"; -// DB Modules -import { GenerateAvatarImage } from "../utils/imageProcessing.js"; -import { ParseBoolean } from "../utils/utils.js"; - -// Models -import InviteToken from "../db/models/Invite.js"; -import Team from "../db/models/Team.js"; -import MaintenanceWindow from "../db/models/MaintenanceWindow.js"; -import MonitorStats from "../db/models/MonitorStats.js"; -import NotificationModel from "../db/models/Notification.js"; -import RecoveryToken from "../db/models/RecoveryToken.js"; - // repositories import { MongoMonitorsRepository, @@ -176,7 +164,7 @@ export const initializeServices = async ({ const bufferService = new BufferService({ logger, checkService, settingsService }); - const statusService = new StatusService({ logger, buffer: bufferService, monitorsRepository }); + const statusService = new StatusService(logger, bufferService, monitorsRepository, monitorStatsRepository, checksRepository); const webhookProvider = new WebhookProvider(logger); const slackProvider = new SlackProvider(logger); diff --git a/server/src/controllers/settingsController.ts b/server/src/controllers/settingsController.ts index 0a01daa0c..3cbfd3f6d 100644 --- a/server/src/controllers/settingsController.ts +++ b/server/src/controllers/settingsController.ts @@ -8,11 +8,9 @@ class SettingsController { static SERVICE_NAME = SERVICE_NAME; private settingsService: any; private emailService: any; - private db: any; - constructor(settingsService: any, emailService: any, db: any) { + constructor(settingsService: any, emailService: any) { this.settingsService = settingsService; this.emailService = emailService; - this.db = db; } get serviceName() { diff --git a/server/src/repositories/monitor-stats/IMonitorStatsRepository.ts b/server/src/repositories/monitor-stats/IMonitorStatsRepository.ts index 08309b4ee..c718e7eb3 100644 --- a/server/src/repositories/monitor-stats/IMonitorStatsRepository.ts +++ b/server/src/repositories/monitor-stats/IMonitorStatsRepository.ts @@ -1,6 +1,7 @@ import type { MonitorStats } from "@/types/index.js"; export interface IMonitorStatsRepository { // create + create(data: Omit): Promise; // single fetch findByMonitorId(monitorId: string): Promise; // update diff --git a/server/src/repositories/monitor-stats/MongoMonitorStatsRepository.ts b/server/src/repositories/monitor-stats/MongoMonitorStatsRepository.ts index 52dbe8aa5..7211c7d89 100644 --- a/server/src/repositories/monitor-stats/MongoMonitorStatsRepository.ts +++ b/server/src/repositories/monitor-stats/MongoMonitorStatsRepository.ts @@ -32,6 +32,11 @@ class MongoMonitorStatsRepository implements IMonitorStatsRepository { }; }; + create = async (data: Omit): Promise => { + const created = await MonitorStatsModel.create(data); + return this.toEntity(created); + }; + findByMonitorId = async (monitorId: string): Promise => { const monitorStats = await MonitorStatsModel.findOne({ monitorId: new mongoose.Types.ObjectId(monitorId) }); if (!monitorStats) { diff --git a/server/src/service/infrastructure/bufferService.ts b/server/src/service/infrastructure/bufferService.ts index 461001800..415c22281 100755 --- a/server/src/service/infrastructure/bufferService.ts +++ b/server/src/service/infrastructure/bufferService.ts @@ -2,7 +2,14 @@ import type { Check } from "@/types/index.js"; const SERVICE_NAME = "BufferService"; -class BufferService { +export interface IBufferService { + addToBuffer(check: Check): void; + removeCheckFromBuffer(check: Check): boolean; + scheduleNextFlush(): void; + flushBuffer(): Promise; +} + +class BufferService implements IBufferService { static SERVICE_NAME = SERVICE_NAME; private BUFFER_TIMEOUT: number; private logger: any; @@ -13,7 +20,6 @@ class BufferService { constructor({ logger, checkService, settingsService }: { logger: any; checkService: any; settingsService: any }) { this.BUFFER_TIMEOUT = settingsService.getSettings().nodeEnv === "development" ? 10 : 1000 * 60 * 1; // 1 minute - console.log(this.BUFFER_TIMEOUT); this.logger = logger; this.checksService = checkService; this.SERVICE_NAME = SERVICE_NAME; @@ -30,7 +36,7 @@ class BufferService { return BufferService.SERVICE_NAME; } - addToBuffer({ check }: { check: Check }) { + addToBuffer(check: Check) { try { this.buffer.push(check); } catch (error: any) { diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index 284fd3ff7..66b12a315 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -1,6 +1,4 @@ -import { IMonitorsRepository } from "@/repositories/index.js"; -import MonitorStats from "../../db/models/MonitorStats.js"; -import { CheckModel } from "@/db/models/index.js"; +import { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository } from "@/repositories/index.js"; import type { Monitor, MonitorStatus, @@ -10,7 +8,9 @@ import type { HardwareStatusPayload, PageSpeedStatusPayload, CheckSnapshot, + MonitorStats, } from "@/types/index.js"; +import { ILogger } from "@/utils/logger.js"; const SERVICE_NAME = "StatusService"; export interface IStatusService { @@ -27,11 +27,21 @@ export class StatusService implements IStatusService { private logger: any; private buffer: any; private monitorsRepository: IMonitorsRepository; + private monitorStatsRepository: IMonitorStatsRepository; + private checksRepository: IChecksRepository; - constructor({ logger, buffer, monitorsRepository }: { logger: any; buffer: any; monitorsRepository: IMonitorsRepository }) { + constructor( + logger: ILogger, + buffer: any, + monitorsRepository: IMonitorsRepository, + monitorStatsRepository: IMonitorStatsRepository, + checksRepository: IChecksRepository + ) { this.logger = logger; this.buffer = buffer; this.monitorsRepository = monitorsRepository; + this.monitorStatsRepository = monitorStatsRepository; + this.checksRepository = checksRepository; } get serviceName() { @@ -42,18 +52,17 @@ export class StatusService implements IStatusService { try { const monitorId = monitor.id; const { responseTime, status } = networkResponse; - // Get stats - let stats = await MonitorStats.findOne({ monitorId }); + let stats = await this.monitorStatsRepository.findByMonitorId(monitorId); if (!stats) { - stats = new MonitorStats({ + stats = { monitorId, avgResponseTime: 0, totalChecks: 0, totalUpChecks: 0, totalDownChecks: 0, uptimePercentage: 0, - lastCheck: null, - }); + lastResponseTime: 0, + }; } // Update stats From b6b1b8464c9e871c42dd3c610cd196d529dcc312 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 23:03:16 +0000 Subject: [PATCH 23/58] remove old DB references --- server/src/repositories/checks/IChecksRepository.ts | 1 + .../src/repositories/checks/MongoChecksRepistory.ts | 5 +++++ server/src/service/infrastructure/statusService.ts | 11 +++++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/server/src/repositories/checks/IChecksRepository.ts b/server/src/repositories/checks/IChecksRepository.ts index 74def03c2..b75b18f13 100644 --- a/server/src/repositories/checks/IChecksRepository.ts +++ b/server/src/repositories/checks/IChecksRepository.ts @@ -11,6 +11,7 @@ import type { LatestChecksMap } from "@/repositories/checks/MongoChecksRepistory export interface IChecksRepository { // create + create(check: Check): Promise; createChecks(checks: Check[]): Promise; // single fetch diff --git a/server/src/repositories/checks/MongoChecksRepistory.ts b/server/src/repositories/checks/MongoChecksRepistory.ts index a36788e2c..c9cdbffd6 100644 --- a/server/src/repositories/checks/MongoChecksRepistory.ts +++ b/server/src/repositories/checks/MongoChecksRepistory.ts @@ -227,6 +227,11 @@ class MongoChecksRepository implements IChecksRepository { } as unknown as CheckDocument; }; + create = async (check: Check) => { + const savedCheck = await CheckModel.create(check); + return this.toEntity(savedCheck); + }; + createChecks = async (checks: Check[]) => { const docs = checks.map((check) => this.toDocument(check)); const inserted = await CheckModel.insertMany(docs); diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index 66b12a315..de8fb9963 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -52,7 +52,7 @@ export class StatusService implements IStatusService { try { const monitorId = monitor.id; const { responseTime, status } = networkResponse; - let stats = await this.monitorStatsRepository.findByMonitorId(monitorId); + let stats: Omit = await this.monitorStatsRepository.findByMonitorId(monitorId); if (!stats) { stats = { monitorId, @@ -62,6 +62,7 @@ export class StatusService implements IStatusService { totalDownChecks: 0, uptimePercentage: 0, lastResponseTime: 0, + lastCheckTimestamp: 0, }; } @@ -105,8 +106,7 @@ export class StatusService implements IStatusService { // latest check stats.lastCheckTimestamp = new Date().getTime(); - - await stats.save(); + await this.monitorStatsRepository.create(stats); return true; } catch (error: any) { this.logger.error({ @@ -121,11 +121,10 @@ export class StatusService implements IStatusService { handleIncidentForCheck = async (check: Check, monitor: Monitor, action: any, errorContext = "incident handling") => { try { - let savedCheck; + let savedCheck: Check | null = null; if (!check.id) { try { - const checkModel = new CheckModel(check); - savedCheck = await checkModel.save(); + savedCheck = await this.checksRepository.create(check); this.buffer.removeCheckFromBuffer(check); } catch (checkError: any) { From 5ab5cbe622a35dcffa52194b433e7a2c7140b280 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 23:31:37 +0000 Subject: [PATCH 24/58] status box fix --- client/package-lock.json | 8 ++++--- .../v2/design-elements/StatusBox.tsx | 24 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 84fc4c3a6..038814543 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2472,11 +2472,13 @@ } }, "node_modules/axios": { - "version": "1.13.4", + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, diff --git a/client/src/Components/v2/design-elements/StatusBox.tsx b/client/src/Components/v2/design-elements/StatusBox.tsx index a83ebcf5d..1be76988b 100644 --- a/client/src/Components/v2/design-elements/StatusBox.tsx +++ b/client/src/Components/v2/design-elements/StatusBox.tsx @@ -2,7 +2,6 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import { BaseBox } from "@/Components/v2/design-elements"; -import Background from "@/assets/Images/background-grid.svg?react"; import { useTranslation } from "react-i18next"; import type { SxProps } from "@mui/material"; @@ -18,6 +17,7 @@ export const BGBox = ({ children, sx }: StatusBoxProps) => { return ( { > - - + top={0} + left={0} + right={0} + bottom={0} + sx={{ + pointerEvents: "none", + backgroundImage: ` + linear-gradient(${theme.palette.divider} 1px, transparent 1px), + linear-gradient(90deg, ${theme.palette.divider} 1px, transparent 1px) + `, + backgroundSize: "24px 24px", + maskImage: + "linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.4) 100%)", + WebkitMaskImage: + "linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.4) 100%)", + }} + /> {children} ); From afe2b9d3bbfbb3e6809d039770daed898d1daf09 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Feb 2026 23:37:08 +0000 Subject: [PATCH 25/58] remove unused images --- client/src/assets/Images/Google.png | Bin 853 -> 0 bytes .../src/assets/Images/avatar_placeholder.png | Bin 5546 -> 0 bytes client/src/assets/Images/background-grid.svg | 67 ------------------ .../assets/Images/create-placeholder-dark.svg | 36 ---------- .../src/assets/Images/create-placeholder.svg | 29 -------- client/src/assets/Images/data_placeholder.svg | 19 ----- .../assets/Images/data_placeholder_dark.svg | 19 ----- .../Images/jupiter_logo_banner_dark.svg | 35 --------- .../Images/jupiter_logo_banner_light.svg | 35 --------- client/src/assets/Images/logo_placeholder.svg | 5 -- .../assets/Images/solana_logo_banner_dark.svg | 24 ------- .../Images/solana_logo_banner_light.svg | 49 ------------- 12 files changed, 318 deletions(-) delete mode 100644 client/src/assets/Images/Google.png delete mode 100644 client/src/assets/Images/avatar_placeholder.png delete mode 100644 client/src/assets/Images/background-grid.svg delete mode 100644 client/src/assets/Images/create-placeholder-dark.svg delete mode 100644 client/src/assets/Images/create-placeholder.svg delete mode 100644 client/src/assets/Images/data_placeholder.svg delete mode 100644 client/src/assets/Images/data_placeholder_dark.svg delete mode 100644 client/src/assets/Images/jupiter_logo_banner_dark.svg delete mode 100644 client/src/assets/Images/jupiter_logo_banner_light.svg delete mode 100644 client/src/assets/Images/logo_placeholder.svg delete mode 100644 client/src/assets/Images/solana_logo_banner_dark.svg delete mode 100644 client/src/assets/Images/solana_logo_banner_light.svg diff --git a/client/src/assets/Images/Google.png b/client/src/assets/Images/Google.png deleted file mode 100644 index 490f4a20138afe2c3aecfbacaf00da91f4086cbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 853 zcmV-b1FHOqP)P000;W1^@s654Bdt00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yPk==P+9lWnZ|dss+$i|$vJS6K&KLTfWdichvkQxGfK`A$x?S@7+-^M zXb{!#(@uL-)ULMJ9ZCNife9{BEk9tF`br0d2nH&6!90L!xdR@?l?TfxI8UCMnoHS@ z_O@%OD-y@ih?8g2H~@ikXzJ7VQhB!Pe4K)iunNM3pp0ZWc5cB~sS?Yb~~j~(Hi05 zVp~YLBOhpX(z9)m8qB#XP>5q$ilri^>7gQtnMld}9^O0)n1Q~12eE0=@^!|EBZeBl8 zt|b@~UWmG$ZX|J4al4!oAzdKbMca5^FX1rZPjK*&~NBRfg3XW}tU@_p?B1FV}-Yb?s?lM#_-!AIqn3iwNq(bTe z5-XyyzBIP(N_UDYC~kM{k4M;Xk4H0)8}_=gU{}n({vtQU&Y1iX91_g8l`{h0`acd{ zD{K3%KN69bu`pw70u@B?0K6&F2Ift%<*g#gK3Vh<{u1?~YM2uUlR_TMGl1KwFajC2 fX^c7@+#>z}qn;xd!^AiT00000NkvXXu0mjf;7fKm diff --git a/client/src/assets/Images/avatar_placeholder.png b/client/src/assets/Images/avatar_placeholder.png deleted file mode 100644 index 38e896811951f0ccf5799097a774793eddb644c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5546 zcmV;b6;zKK6953&V}Wo#O8^7_|6zyU-`{j}bo;@bK|w({I5=TpVcBGUXlQ5`7Z)ljDqCAy z$H&LBv$IAcyv5Ks!oAH0Hmcyrh&?O-5*5Rz@K#90m=1K2K&aJ3cKcA{h=X z5f#Q z?cFUc;dytSXP%jPW}eQ>Ol2xlnaWhAGL@-JWhzto3&_&yy*qaw-B%2;R4SLtrJ87H z>yPiQtuFB%Sr~Hf;kr>5Jfv9C9<1>m;W%>dvEjwmEu}}dd5`o;a_>R87i4i`rBbQG zEUnioD~rXR*Xrx{c#k)ztW~?v>ag%kMbX-l)HKC3s$yxS^Dg60HC^wNJ8(u^C5d-S zI*mU~!+%V%ylB6<_NQUIXRp4+QZ=oq0MjeUBoPuP6Qi`je#2blJ@%30F&k~A3R5v2 z@2D?n^Cbz<`S-XIPpg_zt+3y^%X{?0Wr;1ox~VY$A|xKhmW;aytkIf1RZZRi!{j#U zVx_7o9V$lXNWVVuM?eVkbdl^%DcUo2jhPH3sdNa{UczoAc7B3Ox2%-#w>P4^aoiyT zW2lOvxJ^cHQIXA1G&aSfi%1$=QPM&AfDj!3_*@hNw~ocABCe7NwdZFrKoJ+92EVGN zapS1-M)44Iuq$kPPpZSQI-(>|b0(=?RS;3+&EhH=O;NT#1e>R%!ZKUDYFt6w2fS%q z6+IX zuIR_SiTdO=&QUOiL9HkfqAMe+U4#lTM=ZrrwdZKytuRR*>57(4v#5gzHJqpGyqS6g z_xd_5!oc1P>8sjHsAyOp-auK!SR+C!@jm&@!3kB`DD17USHx(A!;4H0!3jmS2nT)@ka6`Z-Rl`37$|o_bul_222RrFfeG0f z^tQliEjrT_T+*T$4@gJ=7%zJg8qu+)i!@0C5#lzH13*6mtQ4b?Tg2_Y7ASL}s7i%R zQNMR-W!Qsw!;##zW1o=;Rn?@UijsgP}~P2ajyJM2XBo zEMfj>R65ikxT3jSt~zjJ(@%&AnKX4r06Bf=pgwgIa+LvzCO^iV<#7HgR|-V6&3 zM|Rm%70gEw30H;_Qj(uH-V8G|MtZb$sEI|Gpu+Bpww>`KOh&}itb5M8MqUcqL3JVNJ%L7nWiLF)hV(NUNtRCw+TTK z+t!;s_R2=hNV^eKsy`b7tR ztM&IEUmo<5Ik4Q1pf)Ju$!ZNd%ELK#u(=P$Wf-B}RL1PDt?wboP0z4zn3)gHY69A%L3kE6(U zc$Q4r4KSyXaNF!D*@f3QwMcJzBBT3~br3uMmt1la)-w^R75*g)tKD!^T-boEfo%>$ zOpH712@r~^twc=e@ODh^IdB#9N-9F`+37Y&Vr2dGNhTp+G)5(jD&;(Qr%W-lfIZq! zG(2Ge!*FbSFZ$I86BcY58w#FeAtVrPa3-YCLIV#gX}ch=aEBndBH{nSx;7oc692Pq zB2?^>GzrZyj3W5;otVr)v|6{0Sd+2vsbi+_SE<4R(oji0MhC zL&!NNjD)6YXD~2Wy4ptHP52U1%uyl)CyT|tR06Y^*dB}kgArn$5jRAf84)17+eK)G zL%1nWl~fXwQ&Ayg>yS45_hS?4Tg*J;;czqvJLSEMaNKp6Ai^}&d@EJ{gpY}kGQw0I z@>(Ak&?ZC`GD6Pj#K#>SI)q~a+JtJFGIsn4DIuIx!X?bX7E8wC)>h)_kZ%^FvS z);}QXb-bhq99;AelIK0P4v)d}R-;3>4unoaIz~?it#S9m<}RyQR2(OQ^U(|*uC)m< z0zMs^P+-lLN<11hrr3wz)KIc4#<;We@07)0Dx`)Q&V*E$$b1@hWP36uAUNJdtg-44 za&BTHLRN;MQ26v}OhW4idxuRsgq#l$H3-NZ9a2X4ur-{*m+=3{lrsAq1wzGcJ0!un zWuZA9;Ttf{Wn6|th)x9Ox-WwW?Gt=Tt29P9PxDdXiJgG8_k4l-A#l~H+iT}B##@M( zhZ2-_k3s|pVS`xdTtS09bvbK{9WnE9(e`LqnU%`F5W0lD79Bz?(>fYQhYbN+8#=X| z8{B&?uoSyf&rCkZD}DRQfHX;s4x!5Zn44-ZyDGM^e|Puv>MA_N#A0zIl=W1m<~w0%Y!LqJ+`iR27Jg)vgmo~whzJec#WDZdJ3S?Hc-V$ za6TPX2*GdHjc)uCrj#!2=|i9m9?*%!z|**!zzHc` zw=mgV@2!R=*PCl_A)?dPO9(45Cp>!-^!y2Qh-HZe)~$3s4D)wf-L?w#D)%-bkcAfm zXQZrS>=aUz-p*k3bgLWzS82oVBUI=zkJkayiaI9q7nK3RI^Vi4tQQjd?;5ag5_l7A z!}x$z!G<i^9s!`slH+{xK)8e(63@IiFmBDb1w^2^D1p5dYsA zImT$79t(6^-yosMH;(}euHw>{M_IR=@Y2!~BTQ9LbaM~Oa9wX7P`F+m!3>RC=OOOY zh&ajwO>DP*5y)M0Bc$vWw}r?WWZekqE~}jI4=XWTi&l&JpPswljzX>N+!mrqhZe3K zz-dLqKA3+thr4g5|0KY)J0Znm_c;Ns3eE*zZh{GjoN%*Yc_&b}vDFgYZA$jI_t{dL zC9e<>Cu!BQ6CYh0+ydTu$HUtR{gir1>4F6>!WzG6ik-{eZM^LM8Ia!^ZG+R(J_7$( zC%@Zos(SUiv(pehZ6$XoAouLV2g0K8f`)(CXu(v?Y;U&-vH#Gr8q}IcZ!)}QyFynh z@F|SK*<*P3sT1M;CR5SD`%~B)w^@NZb_yk|{jJ~FYg_+n6T0=vCdsWaIRIj1XIy?yHl)@#+X-^a|ra8(2AHo?euCH25!Mx zqq)c$(uyyB`SsUdUbLGNg~KBYw23Zh+=DP~`=;05c0m_#yY^r^j-e^lN zwp$7XyOnaUf!(ti?B-g*LrAZ?K+aIS3WcJt3Nh4wWsyzMtv6eTLZ9qyy|MHR z_76GdP2SJKT!!#q<~q}g>&%h#ydelIAo`O>PG2+j!X9nDJU;mS=FQ!M<6nPjSQcxU z#RjR@px>J6bGs{xIIl5Zv-E^EX)1Dc9}>Hl2l zL`KPn0}O$kqHmuNBa>u@FtiO-Zhr)te3m|NN+$9hw}jlGb0d!yv9so zRrNMD9WSu_Xl+6kXHBWLn|&*W_a$UDU{3fOhWMiu?q?D|;72k9(R8lZ5Xy!b{(N2P z*!h*J=EDc0BsYelUzZC8+(f5dAe{Psdxol2JKrr7{;8tV@Vi(t28IE9nW`q^s;1(9 z*o}e5A04AIQffHUJjPT_-BjB$h^Q%=QF0uj@Tcknnw}=L!}hE}yb52_%xYDv(buXm zcf}$bI-(9yjTU*Ti};mSrBY24t5q}J%ZgtN0)NR6akWe$o}yj8-pNX{8%Q+#zPOd1 zhIK&Pgs?YYRzG9C>UVp<8?BVYs;MzbmHlmvz8_*DHkA;IqShf)4YAU3ql<0AA6i!^ zjLNir9YkcDWzl5cDM5m(U_uGT2W>;D#uZoXW(qStwp`*iR9+V|RrEfH& zTL~w2F1%*{wVGinU3N|Q{PcWw=W?!4C`gj@6o2yk<4D=y4qwLF6LLl2Rv|A*@SM5J z<(=8{i?dJNpIpr_>^s9Ix9>BL6!qpz&f?QqK+ET4l$e~&W~E#B^W%Lhz!9RZ@6&d1 zF3Hs{d&l+R0r%jMaNFZ~LgsPnca3Z1)Sg!9XS6q}!q!FXaZ`k!nnC7t6-yC1N? zZG=WI9WP*L++=|BStj<=;Mw!@S!r(PX&2vD#SOY{^$Ap5tGw(r_-mb&aQ2WNG;mo2kw1q32JS zl==-HxOkb*cAk;#e`q#a*g0cLoN(p$?L{2Umv0hkYhWBq=Hm(D-8uyD0?Hq3#djk4F_9ID>2X?40xwo2QVYx9kT_Xa=82m zab-x$6GWsC>TJPhF7+VhzdA<#m&R$cT^)_*`mb>R#C-b5xU z9+KQB_}GJP$s*$=GNM*FPXO>$2=@^zs$?>0xSTbG66t5 zPAeAtEMAX*Uosz)E-!?RkFfjh;NW1__J;7kZe5bcU=xmn2yagR_HOW6uTQWDgA$^L39}W#h41Ho{2S!y`S<081u09m zkrB$l2tlMjgwRvO8hmOy`H`(&mpB8L^R~3-dEiI2e^LJW3C0tu5^)voN~7C#kAeAl z34tDz-w{GC%zOk7+zDlLVF>O-VShJU1y|wdHhuDv{|ph1|JfNNLy z6ly~aCfdHCX^0GAHjBB0@G>?l5EB;Wd2@A3Dt0M^*qw-$^j1C!%43y&PQsu04dxE>%bd=!wb-1 zPAW1k2)U>bP6lwe4r4nZC8LHBP6&`rnEVJ+ zvE?ucW7kfYx@JN-Hn<=1)?sQHf{XBU=yt9)*>yNagx;?sVVJYj<YCqtO}%M%XOAzO!G zSQ<}4+m=o$gEQ2YhPEHBQuO2!{Z4p49BNBL+bxJN|5qktS&Zu^9J&ruVR_!12#4Cz zR4lCM3D3AAsl!kSFC@1-8(+UPya;%v?m@`eFAb5fJcN*!UrL0b9IurytM5n1$)|~h zm21O$OwOeFkqARPy%}yxQ-5;8>(n8gu6f&1r}Zi37DJ99b3^kq-@~e?@gkI62t!1i z87`^?O4htdkia zEDASV - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/create-placeholder-dark.svg b/client/src/assets/Images/create-placeholder-dark.svg deleted file mode 100644 index 2dd68750b..000000000 --- a/client/src/assets/Images/create-placeholder-dark.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/create-placeholder.svg b/client/src/assets/Images/create-placeholder.svg deleted file mode 100644 index bdd9ef945..000000000 --- a/client/src/assets/Images/create-placeholder.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/data_placeholder.svg b/client/src/assets/Images/data_placeholder.svg deleted file mode 100644 index bf840b95f..000000000 --- a/client/src/assets/Images/data_placeholder.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/data_placeholder_dark.svg b/client/src/assets/Images/data_placeholder_dark.svg deleted file mode 100644 index 7e2a811d5..000000000 --- a/client/src/assets/Images/data_placeholder_dark.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/jupiter_logo_banner_dark.svg b/client/src/assets/Images/jupiter_logo_banner_dark.svg deleted file mode 100644 index 3d3e23b14..000000000 --- a/client/src/assets/Images/jupiter_logo_banner_dark.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/jupiter_logo_banner_light.svg b/client/src/assets/Images/jupiter_logo_banner_light.svg deleted file mode 100644 index 4744e0bcb..000000000 --- a/client/src/assets/Images/jupiter_logo_banner_light.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/logo_placeholder.svg b/client/src/assets/Images/logo_placeholder.svg deleted file mode 100644 index 82f307b2d..000000000 --- a/client/src/assets/Images/logo_placeholder.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/client/src/assets/Images/solana_logo_banner_dark.svg b/client/src/assets/Images/solana_logo_banner_dark.svg deleted file mode 100644 index 08ec87cb1..000000000 --- a/client/src/assets/Images/solana_logo_banner_dark.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/src/assets/Images/solana_logo_banner_light.svg b/client/src/assets/Images/solana_logo_banner_light.svg deleted file mode 100644 index 774018a6a..000000000 --- a/client/src/assets/Images/solana_logo_banner_light.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From dfc1733820d33dd9e1383b2957d5012827638dce Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 13 Feb 2026 18:51:29 +0000 Subject: [PATCH 26/58] remove icons --- client/src/assets/icons/discord-icon.svg | 8 -------- client/src/assets/icons/slack-icon.svg | 10 ---------- client/src/assets/icons/upt_logo.png | Bin 438683 -> 0 bytes client/src/assets/icons/zapier-icon.svg | 8 -------- 4 files changed, 26 deletions(-) delete mode 100644 client/src/assets/icons/discord-icon.svg delete mode 100644 client/src/assets/icons/slack-icon.svg delete mode 100644 client/src/assets/icons/upt_logo.png delete mode 100644 client/src/assets/icons/zapier-icon.svg diff --git a/client/src/assets/icons/discord-icon.svg b/client/src/assets/icons/discord-icon.svg deleted file mode 100644 index c03e8e127..000000000 --- a/client/src/assets/icons/discord-icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/client/src/assets/icons/slack-icon.svg b/client/src/assets/icons/slack-icon.svg deleted file mode 100644 index ff256fd4d..000000000 --- a/client/src/assets/icons/slack-icon.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/client/src/assets/icons/upt_logo.png b/client/src/assets/icons/upt_logo.png deleted file mode 100644 index d443d0897b123ed3bbca27a609a28695b51a749c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 438683 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 z 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
@;qbI!nt+G-H%(O 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
Lk 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%0D_0*ziGcK1mvc+P$x%phHc^ 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˄HMh0AE297#X)t0VuO$iLWR0})thix?##WO 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 diff --git a/client/src/assets/icons/zapier-icon.svg b/client/src/assets/icons/zapier-icon.svg deleted file mode 100644 index 6ee0b5eca..000000000 --- a/client/src/assets/icons/zapier-icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file From 13251ca7c581d6e03bce6aa52505cffdd5dc8bfa Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 13 Feb 2026 19:04:19 +0000 Subject: [PATCH 27/58] fix initializing stats --- server/src/service/infrastructure/statusService.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index de8fb9963..0ab47f85b 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -52,7 +52,18 @@ export class StatusService implements IStatusService { try { const monitorId = monitor.id; const { responseTime, status } = networkResponse; - let stats: Omit = await this.monitorStatsRepository.findByMonitorId(monitorId); + let stats: Omit | null = null; + stats = await this.monitorStatsRepository + .findByMonitorId(monitorId) + .then((result) => result) + .catch(() => { + this.logger.debug({ + service: SERVICE_NAME, + method: "updateRunningStats", + message: `No existing stats found for monitor ${monitorId}, initializing new stats.`, + }); + return null; + }); if (!stats) { stats = { monitorId, From bd941db771fdfbeeb63cb47527c74f151e6b4cc5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 13 Feb 2026 20:41:27 +0000 Subject: [PATCH 28/58] clean up strings --- scripts/flatten-locales.js | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 scripts/flatten-locales.js diff --git a/scripts/flatten-locales.js b/scripts/flatten-locales.js new file mode 100644 index 000000000..ba8d5d16c --- /dev/null +++ b/scripts/flatten-locales.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); + +function flattenKeys(obj, prefix = "", result = []) { + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const newKey = prefix ? `${prefix}.${key}` : key; + + if ( + typeof obj[key] === "object" && + obj[key] !== null && + !Array.isArray(obj[key]) + ) { + flattenKeys(obj[key], newKey, result); + } else { + result.push(newKey); + } + } + } + return result; +} + +// Paths +const localesDir = path.join(__dirname, "../client/src/locales"); +const inputPath = path.join(localesDir, "en.json"); +const outputPath = path.join(localesDir, "keys.json"); + +try { + const jsonContent = fs.readFileSync(inputPath, "utf8"); + const jsonData = JSON.parse(jsonContent); + + const flattenedKeys = flattenKeys(jsonData); + flattenedKeys.sort(); + + fs.writeFileSync(outputPath, JSON.stringify(flattenedKeys, null, 2), "utf8"); + + console.log(`Keys written to: ${outputPath}`); +} catch (error) { + console.error(error.message); + process.exit(1); +} From fd2c54d3d3e2c8009ed53d33a0aaf7434625aa0f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 13 Feb 2026 20:42:26 +0000 Subject: [PATCH 29/58] remove unused --- .../src/Components/v2/inputs/ImageUpload.tsx | 10 +- .../src/Pages/Auth/SetNewPassword/index.tsx | 14 +- client/src/Pages/CreateMonitor/index.tsx | 90 +- .../Incidents/Components/DialogResolution.tsx | 9 +- .../Maintenance/MaintenanceWindowTable.tsx | 4 +- .../Components/HeaderStatusPageControls.tsx | 2 +- client/src/Pages/StatusPage/Status/index.tsx | 1 - client/src/Utils/MonitorUtils.ts | 37 - client/src/Validation/login.ts | 7 +- client/src/Validation/recovery.ts | 5 +- client/src/locales/en.json | 771 ++---------------- 11 files changed, 172 insertions(+), 778 deletions(-) diff --git a/client/src/Components/v2/inputs/ImageUpload.tsx b/client/src/Components/v2/inputs/ImageUpload.tsx index 6c9fc1783..0d0b77b40 100644 --- a/client/src/Components/v2/inputs/ImageUpload.tsx +++ b/client/src/Components/v2/inputs/ImageUpload.tsx @@ -38,11 +38,11 @@ export const ImageUpload = ({ const isValidType = accept.some((type) => file.type.includes(type)); const isValidSize = file.size <= maxSize; if (!isValidType) { - setLocalError(t("common.errors.invalidFileFormat")); + setLocalError(t("components.imageUpload.errors.invalidFileFormat")); return; } if (!isValidSize) { - setLocalError(t("common.errors.invalidFileSize")); + setLocalError(t("components.imageUpload.errors.invalidFileSize")); return; } setLocalError(null); @@ -137,15 +137,15 @@ export const ImageUpload = ({ color="primary" fontWeight={500} > - {t("common.imageUpload.clickToUpload")} + {t("components.imageUpload.clickToUpload")} {" "} - {t("common.imageUpload.orDragAndDrop")} + {t("components.imageUpload.orDragAndDrop")} - {accept.join(", ").toUpperCase()} • {t("common.imageUpload.maxSize")}{" "} + {accept.join(", ").toUpperCase()} • {t("components.imageUpload.maxSize")}{" "} {Math.round(maxSize / 1024 / 1024)}MB diff --git a/client/src/Pages/Auth/SetNewPassword/index.tsx b/client/src/Pages/Auth/SetNewPassword/index.tsx index 09bd565f1..2e99be254 100644 --- a/client/src/Pages/Auth/SetNewPassword/index.tsx +++ b/client/src/Pages/Auth/SetNewPassword/index.tsx @@ -97,27 +97,27 @@ const SetNewPasswordPage = () => { /> @@ -127,7 +127,7 @@ const SetNewPasswordPage = () => { fullWidth loading={loading} > - {t("auth.forgotPassword.buttons.resetPassword")} + {t("common.buttons.resetPassword")} { value={field.value ?? ""} onChange={(e) => field.onChange(Number(e.target.value) || 0)} type="number" - fieldLabel={t("portToMonitor")} - placeholder="5173" + fieldLabel={t("pages.createMonitor.form.general.option.port.label")} + placeholder={t( + "pages.createMonitor.form.general.option.port.placeholder" + )} fullWidth error={!!fieldState.error} helperText={fieldState.error?.message ?? ""} @@ -351,10 +353,12 @@ const CreateMonitorPage = () => { )} /> @@ -617,11 +661,21 @@ const CreateMonitorPage = () => { "pages.createMonitor.form.advanced.option.matchMethod.label" )} > - {t("matchMethodOptions.equal")} - - {t("matchMethodOptions.include")} + + {t( + "pages.createMonitor.form.advanced.option.matchMethod.equal" + )} + + + {t( + "pages.createMonitor.form.advanced.option.matchMethod.include" + )} + + + {t( + "pages.createMonitor.form.advanced.option.matchMethod.regex" + )} - {t("matchMethodOptions.regex")} )} /> diff --git a/client/src/Pages/Incidents/Components/DialogResolution.tsx b/client/src/Pages/Incidents/Components/DialogResolution.tsx index 648af52a9..a102b1de3 100644 --- a/client/src/Pages/Incidents/Components/DialogResolution.tsx +++ b/client/src/Pages/Incidents/Components/DialogResolution.tsx @@ -46,10 +46,9 @@ export const DialogResolution = ({ return ( setComment(e.target.value)} fullWidth diff --git a/client/src/Pages/Maintenance/MaintenanceWindowTable.tsx b/client/src/Pages/Maintenance/MaintenanceWindowTable.tsx index 42378bb67..876969d3d 100644 --- a/client/src/Pages/Maintenance/MaintenanceWindowTable.tsx +++ b/client/src/Pages/Maintenance/MaintenanceWindowTable.tsx @@ -196,13 +196,13 @@ export const MaintenanceWindowTable = ({ /> { setDeleteDialogOpen(false); setSelectedWindow(null); }} onConfirm={handleDelete} - confirmText={t("delete")} loading={deleteLoading} /> diff --git a/client/src/Pages/StatusPage/Status/Components/HeaderStatusPageControls.tsx b/client/src/Pages/StatusPage/Status/Components/HeaderStatusPageControls.tsx index d738671ac..0e8f444c9 100644 --- a/client/src/Pages/StatusPage/Status/Components/HeaderStatusPageControls.tsx +++ b/client/src/Pages/StatusPage/Status/Components/HeaderStatusPageControls.tsx @@ -64,7 +64,7 @@ export const HeaderStatusPageControls = ({ }, }} > - {t("publicLink")} + {t("components.headerStatusPageControls.publicLink")} diff --git a/client/src/Pages/StatusPage/Status/index.tsx b/client/src/Pages/StatusPage/Status/index.tsx index 1b509507e..b1826b867 100644 --- a/client/src/Pages/StatusPage/Status/index.tsx +++ b/client/src/Pages/StatusPage/Status/index.tsx @@ -96,7 +96,6 @@ const StatusPageView = () => { }} /> )} - {t("statusPageStatusServiceStatus")} { ? `${strippedUrl.slice(0, maxLength)}…` : strippedUrl; }; - -export interface IStatusPageHeaderConfig { - paletteKey: PaletteKey; - message: string; -} -export const getStatusPageHeaderConfig = ( - monitors: Monitor[], - t: any -): IStatusPageHeaderConfig => { - if (!monitors || monitors.length === 0) { - return { paletteKey: "error", message: "No monitors available" }; - } - - const allUp = monitors.every((monitor) => monitor.status === "up"); - const anyDown = monitors.some((monitor) => monitor.status === "down"); - const allDown = monitors.every((monitor) => monitor.status === "down"); - - if (allUp) - return { - paletteKey: "success", - message: t("statusPage.details.statusHeader.allUp"), - }; - if (allDown) - return { - paletteKey: "error", - message: t("statusPage.details.statusHeader.allDown"), - }; - if (anyDown) - return { - paletteKey: "warning", - message: t("statusPage.details.statusHeader.anyDown"), - }; - return { - paletteKey: "warning", - message: t("statusPage.details.statusHeader.anyDown"), - }; -}; diff --git a/client/src/Validation/login.ts b/client/src/Validation/login.ts index 03eb8d4e2..f14463734 100644 --- a/client/src/Validation/login.ts +++ b/client/src/Validation/login.ts @@ -2,11 +2,10 @@ import { z } from "zod"; export const loginSchema = z.object({ email: z - .string() - .min(1, "auth.common.inputs.email.errors.empty") - .email("auth.common.inputs.email.errors.invalid") + .email("Please enter a valid email address") + .min(1, "Please enter your email address") .transform((val) => val.toLowerCase().trim()), - password: z.string().min(1, "auth.common.inputs.password.errors.empty"), + password: z.string().min(1, "Please enter your password"), }); export type LoginFormData = z.infer; diff --git a/client/src/Validation/recovery.ts b/client/src/Validation/recovery.ts index 356f28738..4a244ed66 100644 --- a/client/src/Validation/recovery.ts +++ b/client/src/Validation/recovery.ts @@ -2,9 +2,8 @@ import { z } from "zod"; export const recoverySchema = z.object({ email: z - .string() - .min(1, "auth.common.inputs.email.errors.empty") - .email("auth.common.inputs.email.errors.invalid") + .email("Please enter a valid email address") + .min(1, "Please enter your email address") .transform((val) => val.toLowerCase().trim()), }); diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 7eb833308..935077a2b 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -1,189 +1,4 @@ { - "aboutus": "About Us", - "access": "Access", - "actions": "Actions", - "add": "Add", - "addMonitors": "Add monitors", - "advancedMatching": "Advanced matching", - "area": "Area", - "auth": { - "common": { - "errors": { - "validation": "Error validating data." - }, - "fields": { - "role": { - "errors": { - "min": "At least one role is required" - } - } - }, - "inputs": { - "email": { - "errors": { - "empty": "To continue, please enter your email address", - "invalid": "Please recheck validity of entered email address" - }, - "label": "Email", - "placeholder": "jordan.ellis@domain.com" - }, - "firstName": { - "errors": { - "empty": "Please enter your name", - "length": "Name must be less than 50 characters", - "pattern": "Name must contain only letters, spaces, apostrophes, or hyphens" - }, - "label": "Name", - "placeholder": "Jordan" - }, - "lastName": { - "errors": { - "empty": "Please enter your surname", - "length": "Surname must be less than 50 characters", - "pattern": "Surname must contain only letters, spaces, apostrophes, or hyphens" - }, - "label": "Surname", - "placeholder": "Ellis" - }, - "password": { - "errors": { - "empty": "Please enter your password", - "length": "Password must be at least 8 characters long", - "lowercase": "Password must contain at least 1 lowercase letter", - "number": "Password must contain at least 1 number", - "special": "Password must contain at least 1 special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)", - "uppercase": "Password must contain at least 1 uppercase letter" - }, - "label": "Password", - "rules": { - "length": { - "beginning": "Must be at least", - "highlighted": "8 characters long" - }, - "lowercase": { - "beginning": "Must contain at least", - "highlighted": "one lower character" - }, - "match": { - "beginning": "Passwords", - "highlighted": "must match" - }, - "number": { - "beginning": "Must contain at least", - "highlighted": "one number" - }, - "special": { - "beginning": "Must contain at least", - "highlighted": "one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)" - }, - "uppercase": { - "beginning": "Must contain at least", - "highlighted": "one upper character" - } - } - }, - "passwordConfirm": { - "errors": { - "different": "Entered passwords don't match, so one of them is probably mistyped", - "empty": "Please enter your password again for confirmation (helps with typos)" - }, - "label": "Confirm password", - "placeholder": "Re-enter password to confirm" - } - }, - "navigation": { - "continue": "Continue" - }, - "passwordRules": { - "length": "Must be at least 8 characters long", - "special": "Must contain at least one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)", - "number": "Must contain at least one number", - "uppercase": "Must contain at least one upper character", - "lowercase": "Must contain at least one lower character", - "match": "Passwords must match" - } - }, - "forgotPassword": { - "buttons": { - "openEmail": "Open email app", - "resetPassword": "Reset password" - }, - "heading": "Forgot password?", - "links": { - "login": "Go back to Log In", - "resend": "Didn't receive the email? Click to resend" - }, - "subheadings": { - "stepFour": "Your password has been successfully reset. Click below to log in magically.", - "stepOne": "No worries, we'll send you reset instructions.", - "stepThree": "Your new password must be different from previously used passwords.", - "stepTwo": "We sent a password reset link to " - }, - "toasts": { - "emailNotFound": "Email not found.", - "error": "Unable to reset password. Please try again later or contact support.", - "redirect": "Redirecting in ...", - "sent": "Instructions sent to .", - "success": "Your password was reset successfully." - } - }, - "login": { - "errors": { - "password": { - "incorrect": "The password you provided does not match our records" - } - }, - "heading": "Log in to continue", - "links": { - "forgotPassword": "Forgot password?", - "forgotPasswordLink": "Reset password", - "register": "Do not have an account?", - "registerLink": "Register here" - }, - "toasts": { - "incorrectPassword": "Incorrect password", - "success": "Welcome back! You're successfully logged in." - }, - "welcome": "Welcome back to Checkmate!" - }, - "registration": { - "description": { - "superAdmin": "Create your super admin account to get started", - "user": "Sign up as a user and ask super admin for access to your monitors" - }, - "heading": { - "user": "Sign Up" - }, - "toasts": { - "success": "Welcome! Your account was created successfully." - }, - "welcome": "Welcome to Checkmate!" - } - }, - "avgCpuTemperature": "Average CPU Temperature", - "bar": "Bar", - "basicInformation": "Basic Information", - "bulkImport": { - "fallbackPage": "Import a file to upload a list of servers in bulk", - "invalidFileType": "Invalid file type", - "noFileSelected": "No file selected", - "selectFile": "Select File", - "selectFileDescription": "You can download our or sample", - "selectFileTips": "Select CSV file to upload", - "title": "Bulk Import", - "uploadFailed": "Upload failed", - "uploadSuccess": "Monitors created successfully!" - }, - "bytesSent": "Bytes Sent", - "addMember": "Add member", - "cancel": "Cancel", - "checkHooks": { - "failureResolveOne": "Failed to resolve incident." - }, - "chooseGame": "Choose game", - "city": "CITY", - "ClickUpload": "Click to upload", - "close": "Close", "common": { "auth": { "roles": { @@ -222,7 +37,8 @@ "testNotifications": "Test notifications", "toggleTheme": "Toggles light & dark", "flushQueue": "Flush queue", - "notFound": "Go to the main dashboard" + "notFound": "Go to the main dashboard", + "resetPassword": "Reset password" }, "charts": { "labels": { @@ -290,28 +106,23 @@ "interval": "Interval", "active": "Active" } - }, - "toasts": { - "checkConnection": "Please check your connection", - "networkError": "Network error", - "unknownError": "Unknown error" - }, + } + }, + "components": { "imageUpload": { "clickToUpload": "Click to upload", "dragAndDrop": "or drag and drop", "supportedFormats": "Supported formats", "maxSize": "Max size", - "orDragAndDrop": "or drag and drop" + "orDragAndDrop": "or drag and drop", + "errors": { + "invalidFileSize": "File size is too large!", + "invalidFileFormat": "Unsupported file format!" + } + }, + "headerStatusPageControls": { + "publicLink": "Public link" }, - "errors": { - "invalidFileType": "Invalid file type", - "fileTooLarge": "File too large" - } - }, - "commonSave": "Save", - "commonSaving": "Saving...", - "companyName": "Company name", - "components": { "headerTimeRange": { "labels": { "day": "Day", @@ -376,229 +187,7 @@ "description": "See the latest releases and help grow the community on GitHub" } }, - "configure": "Configure", - "confirmPassword": "Confirm password", - "cores": "Cores", - "cpu": "CPU", - "cpuFrequency": "CPU Frequency", - "cpuLogical": "CPU (Logical)", - "cpuPhysical": "CPU (Physical)", - "cpuTemperature": "CPU Temperature", - "cpuUsage": "CPU usage", - "createA": "Create a", - "createMaintenance": "Create maintenance", - "createMaintenanceWindow": "Create maintenance window", - "createMonitor": "Create monitor", - "createNew": "Create new", - "delete": "Delete", - "generateToken": "Generate token", - "DeleteAccountButton": "Remove account", - "DeleteAccountTitle": "Remove account", - "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.", - "DeleteDescriptionText": "This will remove the account and all associated data from the server. This isn't reversible.", - "deleteStatusPage": "Do you want to delete this status page?", - "deleteStatusPageConfirm": "Yes, delete status page", - "deleteStatusPageDescription": "Once deleted, your status page cannot be retrieved.", - "DeleteWarningTitle": "Really remove this account?", - "details": "Details", - "device": "Device", - "diagnosticsPage": { - "diagnosticDescription": "System diagnostics", - "gauges": { - "heapAllocationSubtitle": "% of available memory", - "heapAllocationTitle": "Heap allocation", - "heapUsageSubtitle": "% of available memory", - "heapUsageTitle": "Heap usage", - "heapUtilizationSubtitle": "% of allocated", - "heapUtilizationTitle": "Heap utilization", - "instantCpuUsageSubtitle": "% of 1s used by CPU", - "instantCpuUsageTitle": "Instant CPU usage" - }, - "stats": { - "eventLoopDelayTitle": "Event loop delay", - "osMemoryLimitTitle": "OS Memory Limit", - "totalHeapSizeTitle": "Total heap size", - "uptimeTitle": "Uptime", - "usedHeapSizeTitle": "Used heap size" - } - }, - "disk": "Disk", - "diskUsage": "Disk Usage", - "displayName": "Display name", - "download": "Download", - "DragandDrop": "drag and drop", - "duration": "Duration", - "edit": "Edit", - "editing": "Editing...", - "editMaintenance": "Edit maintenance", - "editUserPage": { - "form": { - "email": "Email", - "firstName": "First name", - "lastName": "Last name", - "role": "Roles", - "save": "Save" - }, - "table": { - "actionHeader": "Action", - "roleHeader": "Role" - }, - "title": "Edit user", - "toast": { - "successUserUpdate": "User updated successfully", - "validationErrors": "Validation errors" - } - }, - "EmailDescriptionText": "This is your current email address — it cannot be changed.", - "errorPages": { - "serverUnreachable": { - "alertBox": "Server Connection Error", - "description": "We're unable to connect to the server. Please check your internet connection or verify your deployment configuration if the problem persists.", - "retryButton": { - "default": "Retry connection", - "processing": "Connecting..." - }, - "toasts": { - "reconnected": "Successfully reconnected to the server.", - "stillUnreachable": "Server is still unreachable. Please try again later." - } - } - }, - "errors": "Errors", - "expectedValue": "Expected value", - "failedToSendEmail": "Failed to send email", - "FirstName": "First name", - "frequency": "Frequency", - "friendlyNameInput": "Friendly name", - "friendlyNamePlaceholder": "Maintenance at __ : __ for ___ minutes", - "gb": "GB", - "general": { - "noOptionsFound": "No {{unit}} found" - }, - "greeting": { - "append": "The afternoon is your playground—let's make it epic!", - "overview": "Here's an overview of your {{type}} monitors.", - "prepend": "Hey there" - }, - "high": "high", - "host": "Host", - "http": "HTTP", - "https": "HTTPS", - "incidentsPage": { - "resolveIncidentDialogCommentLabel": "Comment (optional)", - "resolveIncidentDialogCommentPlaceholder": "Add a comment about the resolution...", - "resolveIncidentDialogConfirm": "Resolve", - "resolveIncidentDialogTitle": "Resolve Incident" - }, - "integrations": "Integrations", - "integrationsDiscord": "Discord", - "integrationsDiscordInfo": "Connect with Discord and view incidents directly in a channel", - "integrationsPrism": "Connect Prism to your favorite service.", - "integrationsSlack": "Slack", - "integrationsSlackInfo": "Connect with Slack and see incidents in a channel", - "integrationsZapier": "Zapier", - "integrationsZapierInfo": "Send all incidents to Zapier, and then see them everywhere", - "invalidFileFormat": "Unsupported file format!", - "invalidFileSize": "File size is too large!", - "inviteNoTokenFound": "No invite token found", - "LastName": "Last name", - "logsPage": { - "logLevelSelect": { - "title": "Log level", - "values": { - "all": "All", - "debug": "Debug", - "error": "Error", - "info": "Info", - "warn": "Warn" - } - }, - "noLogs": "No logs found", - "table": { - "level": "Level", - "logs": "logs", - "message": "Message", - "method": "Method", - "service": "Service", - "timestamp": "Timestamp" - }, - "tabs": { - "diagnostics": "Diagnostics", - "logs": "Server logs", - "queue": "Job queue" - }, - "title": "Logs" - }, - "low": "low", - "maintenance": "maintenance", - "maintenanceRepeat": "Maintenance Repeat", - "maintenanceTableActionMenuDialogTitle": "Do you really want to remove this maintenance window?", - "maintenanceWindowDescription": "During maintenance windows, all monitoring is suspended for selected monitors. No network checks will be performed, preventing any status updates or notifications from being triggered. Your monitors will appear frozen at their last known status, and status pages will display a maintenance indicator. Once the maintenance window ends, monitoring automatically resumes, and alerts will trigger if issues are detected. Maintenance periods do not count against uptime calculations.", - "maintenanceWindowName": "Maintenance Window Name", - "matchMethod": "Match Method", - "matchMethodOptions": { - "equal": "Equal", - "include": "Include", - "regex": "Regex" - }, - "MaxSize": "Maximum Size", - "mb": "MB", - "mem": "Mem", - "memory": "Memory", - "memoryUsage": "Memory usage", - "menu": { - "changelog": "Changelog", - "checks": "Checks", - "discussions": "Discussions", - "docs": "Docs", - "incidents": "Incidents", - "inviteMember": "Invite member", - "infrastructure": "Infrastructure", - "logOut": "Log out", - "logs": "Logs", - "maintenance": "Maintenance", - "notifications": "Notifications", - "pagespeed": "Pagespeed", - "password": "Password", - "profile": "Profile", - "settings": "Settings", - "statusPages": "Status pages", - "support": "Support", - "team": "Team", - "uptime": "Uptime" - }, - "message": "Message", - "monitor": "monitor", - "monitorHooks": { - "failureAddDemoMonitors": "Failed to add demo monitors", - "successAddDemoMonitors": "Successfully added demo monitors" - }, - "monitors": "monitors", - "monitorsToApply": "Monitors to apply maintenance window to", - "ms": "ms", - "navControls": "Controls", - "network": "Network", - "nextWindow": "Next window", - "notFoundButton": "Go to the main dashboard", - "notifications": { - "fallback": { - "actionButton": "Create notification channel!", - "checks": [ - "Alert teams about downtime or performance issues", - "Let engineers know when incidents happen", - "Keep administrators informed of system changes" - ], - "title": "A notification channel is used to:" - }, - "fetch": { - "failed": "Failed to fetch notifications" - }, - "test": { - "success": "Test notification sent successfully" - } - }, - "now": "Now", - "os": "OS", + "pages": { "notFound": { "title": "Oh no! You dropped your sushi!", @@ -681,7 +270,32 @@ }, "auth": { "common": { - "passwordRules": {}, + "passwordRules": { + "length": { + "beginning": "Must be at least", + "highlighted": "8 characters long" + }, + "lowercase": { + "beginning": "Must contain at least", + "highlighted": "one lower character" + }, + "match": { + "beginning": "Passwords", + "highlighted": "must match" + }, + "number": { + "beginning": "Must contain at least", + "highlighted": "one number" + }, + "special": { + "beginning": "Must contain at least", + "highlighted": "one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)" + }, + "uppercase": { + "beginning": "Must contain at least", + "highlighted": "one upper character" + } + }, "form": { "option": { "email": { @@ -798,7 +412,10 @@ "label": "JSONPath expression" }, "matchMethod": { - "label": "Match method" + "label": "Match method", + "equal": "Equal", + "include": "Include", + "regex": "Regex" } }, "title": "Advanced settings" @@ -807,7 +424,19 @@ "description": "How often do you want to check the status of this monitor?", "option": { "frequency": { - "label": "Check frequency" + "label": "Check frequency", + "value": { + "fifteenMinutes": "15 minutes", + "fifteenSeconds": "15 seconds", + "fiveMinutes": "5 minutes", + "fourMinutes": "4 minutes", + "oneMinute": "1 minute", + "tenMinutes": "10 minutes", + "thirtyMinutes": "30 minutes", + "thirtySeconds": "30 seconds", + "threeMinutes": "3 minutes", + "twoMinutes": "2 minutes" + } } }, "title": "Check frequency" @@ -833,6 +462,14 @@ "url": { "label": "URL", "placeholder": "https://www.google.com" + }, + "game": { + "label": "Choose game", + "placeholder": "Select a game" + }, + "port": { + "label": "Port to monitor", + "placeholder": 80 } }, "title": "General settings", @@ -897,6 +534,15 @@ }, "incidents": { "dialog": { + "resolveIncident": { + "title": "Resolve incident", + "option": { + "comment": { + "label": "Comment (optional)", + "placeholder": "Add a comment about the resolution..." + } + } + }, "details": { "analysis": "Incident analysis", "comment": "Comment:", @@ -1371,272 +1017,5 @@ "title": "An uptime monitor is used to:" } } - }, - "pageSpeedAddApiKey": "to add your API key.", - "pageSpeedLearnMoreLink": "Click here", - "pageSpeedWarning": "Warning: You haven't added a Google PageSpeed API key yet. Without it, the PageSpeed monitor won't function.", - "passwordPanel": { - "confirmNewPassword": "Confirm new password", - "currentPassword": "Current password", - "enterCurrentPassword": "Enter your current password", - "enterNewPassword": "Enter your new password", - "newPassword": "New password", - "passwordChangedSuccess": "Your password was changed successfully.", - "passwordInputIncorrect": "Your password input was incorrect.", - "passwordRequirements": "New password must contain at least 8 characters and must have at least one uppercase letter, one lowercase letter, one number and one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)." - }, - "pause": "Pause", - "PhotoDescriptionText": "This photo will be displayed in your profile page.", - "portToMonitor": "Port to monitor", - "publicLink": "Public link", - "queuePage": { - "failedJobTable": { - "failCountHeader": "Fail count", - "failedAtHeader": "Last failed at", - "failReasonHeader": "Fail reason", - "monitorIdHeader": "Monitor ID", - "monitorUrlHeader": "Monitor URL", - "title": "Failed jobs" - }, - "flushButton": "Flush queue", - "jobTable": { - "activeHeader": "Active", - "failCountHeader": "Fail count", - "idHeader": "Monitor ID", - "intervalHeader": "Interval", - "lastFinishedAtHeader": "Last finished at", - "lastRunHeader": "Last run at", - "lastRunTookHeader": "Last run took", - "lockedAtHeader": "Locked at", - "runCountHeader": "Run count", - "title": "Jobs currently in queue", - "typeHeader": "Type", - "urlHeader": "URL" - }, - "metricsTable": { - "metricHeader": "Metric", - "title": "Queue metrics", - "valueHeader": "Value" - }, - "refreshButton": "Refresh" - }, - "rate": "Rate", - "remove": "Remove", - "repeat": "Repeat", - "reset": "Reset", - "response": "RESPONSE", - "responseTime": "Response time", - "resume": "Resume", - "roles": { - "admin": "Admin", - "demoUser": "Demo user", - "superAdmin": "Super admin", - "teamMember": "Team member" - }, - "save": "Save", - "sendInvite": "Send invite", - "selectAll": "Select all", - "settingsFailedToClearStats": "Failed to clear stats", - "settingsFailedToDeleteMonitors": "Failed to delete all monitors", - "settingsFailedToSave": "Failed to save settings", - "settingsGeneralSettings": "General settings", - "settingsMonitorsDeleted": "Successfully deleted all monitors", - "settingsPage": { - "aboutSettings": { - "labelDevelopedBy": "Developed by Bluewave Labs", - "title": "About" - }, - "demoMonitorsSettings": { - "buttonAddMonitors": "Add demo monitors", - "description": "Add sample monitors for demonstration purposes.", - "title": "Demo monitors" - }, - "emailSettings": { - "buttonSendTestEmail": "Send test e-mail", - "description": "Configure the email settings for your system. This is used to send notifications and alerts.", - "descriptionTransport": "This builds an SMTP transport for NodeMailer", - "labelAddress": "Email address - Used for authentication", - "labelConnectionHost": "Email connection host - Hostname to use in the HELO/EHLO greeting", - "labelHost": "Email host - Hostname or IP address to connect to", - "labelIgnoreTLS": "Disable STARTTLS: Don't use TLS even if the server supports it", - "labelPassword": "Email password - Password for authentication", - "labelPasswordSet": "Password is set. Click Reset to change it.", - "labelPool": "Enable connection pooling: Reuse existing connections to improve performance", - "labelPort": "Email port - Port to connect to", - "labelRejectUnauthorized": "Reject invalid certificates: Reject connections with self-signed or untrusted certificates", - "labelRequireTLS": "Force STARTTLS: Require TLS upgrade, fail if not supported", - "labelSecure": "Use SSL (recommended): Encrypt the connection using SSL/TLS", - "labelTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP", - "labelUser": "Email user - Username for authentication, overrides email address if specified", - "linkTransport": "See specifications here", - "placeholderUser": "Leave empty if not required", - "title": "Email", - "toastEmailRequiredFieldsError": "Email address, host, port and password are required" - }, - "globalThresholds": { - "description": "Configure global CPU, Memory, Disk, and Temperature thresholds. If a value is provided, it will automatically be enabled for monitoring.", - "title": "Global Thresholds" - }, - "pageSpeedSettings": { - "description": "Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.", - "labelApiKey": "PageSpeed API key", - "labelApiKeySet": "API key is set. Click Reset to change it.", - "title": "Google PageSpeed API key" - }, - "saveButtonLabel": "Save", - "statsSettings": { - "clearAllStatsButton": "Clear all stats", - "clearAllStatsDescription": "Clear all stats. This is irreversible.", - "clearAllStatsDialogConfirm": "Yes, clear all stats", - "clearAllStatsDialogDescription": "Once removed, the monitoring history and stats cannot be retrieved.", - "clearAllStatsDialogTitle": "Do you want to clear all stats?", - "description": "Define how long you want to retain historical data. You can also clear all existing data.", - "title": "Monitor history" - }, - "systemResetSettings": { - "buttonRemoveAllMonitors": "Remove all monitors", - "description": "Remove all monitors from your system.", - "dialogConfirm": "Yes, remove all monitors", - "dialogTitle": "Do you want to remove all monitors?", - "title": "System reset" - }, - "timezoneSettings": { - "description": "Select the timezone used to display dates and times throughout the application.", - "title": "Display timezone" - }, - "title": "Settings", - "uiSettings": { - "chartTypeHeatmap": "Heatmap", - "chartTypeHistogram": "Histogram", - "description": "Switch between light and dark mode, or change user interface language.", - "labelChartType": "Chart type", - "labelLanguage": "Language", - "labelTheme": "Theme mode", - "title": "Appearance" - }, - "urlSettings": { - "description": "Display the IP address or URL of monitor on the public Status page. If it's disabled, only the monitor name will be shown to protect sensitive information.", - "label": "Display IP/URL on status page", - "selectDisabled": "Disabled", - "selectEnabled": "Enabled", - "title": "Monitor IP/URL on Status Page" - } - }, - "settingsStatsCleared": "Stats cleared successfully", - "settingsSuccessSaved": "Settings saved successfully", - "settingsTestEmailFailed": "Failed to send test email", - "settingsTestEmailFailedWithReason": "Failed to send test email: {{reason}}", - "settingsTestEmailSuccess": "Test email sent successfully", - "settingsTestEmailUnknownError": "Unknown error", - "shown": "Shown", - "starPromptDescription": "See the latest releases and help grow the community on GitHub", - "starPromptTitle": "Star Checkmate", - "startTime": "Start time", - "state": "State", - "status": "Status", - "statusCode": "Status code", - "statusPage": { - "contents": "Contents", - "deleteFailed": "Failed to delete status page", - "deleteSuccess": "Status page deleted successfully", - "generalSettings": "General settings", - "details": { - "statusHeader": { - "allUp": "All systems operational", - "allDown": "All systems are experiencing issues", - "anyDown": "Some systems are experiencing issues" - } - } - }, - "statusPageCreate": { - "buttonSave": "Save" - }, - "statusPageStatusServiceStatus": "Service status", - "submit": "Submit", - "SupportedFormats": "Supported formats", - "teamPanel": { - "addTeamMember": { - "addButton": "Add Member", - "addMemberMenu": "Add Team Member", - "description": "Create a new user and share the credentials with them. This method gives the member immediate access to all monitors.", - "title": "Register new team member" - }, - "addMember": "Add member", - "cancel": "Cancel", - "changeTeamPassword": { - "changePasswordMenu": "Reset Password", - "description": "Create a new password for this team member. You will need to share the password with them securely.", - "success": "Password successfully reset. Make sure to provide the credentials to the member in a secure way.", - "title": "Reset team member password" - }, - "email": "Email", - "emailToken": "E-mail token", - "filter": { - "all": "All", - "member": "Member" - }, - "getToken": "Get token", - "inviteDescription": "When you add a new team member, they will get access to all monitors.", - "inviteLink": "Invite link", - "inviteNewTeamMember": "Invite new team member", - "inviteTeamMember": "Invite a team member", - "noMembers": "There are no team members with this role", - "register": "Register a team member", - "registerTeamMember": { - "auth": { - "common": { - "inputs": { - "role": { - "errors": { - "empty": "Role is required" - } - } - } - } - } - }, - "registerToast": { - "success": "User created, share credentials with the member securely." - }, - "role": "Role", - "selectRole": "Select role", - "table": { - "created": "Created", - "email": "Email", - "name": "Name", - "role": "Role" - }, - "teamMembers": "Team members" - }, - "time": { - "fifteenMinutes": "15 minutes", - "fifteenSeconds": "15 seconds", - "fiveMinutes": "5 minutes", - "fourMinutes": "4 minutes", - "oneMinute": "1 minute", - "tenMinutes": "10 minutes", - "thirtyMinutes": "30 minutes", - "thirtySeconds": "30 seconds", - "threeMinutes": "3 minutes", - "twoMinutes": "2 minutes" - }, - "timezone": "Timezone", - "timeZoneInfo": "All dates and times are in GMT+0 time zone.", - "title": "Title", - "total": "Total", - "type": "Type", - "update": "Update", - "uptime": "Uptime", - "url": "URL", - "used": "Used", - "window": "window", - "YourPhoto": "Profile photo", - "failedDeleteMonitor": "Failed to delete monitor", - "failedPauseMonitor": "Failed to pause monitor", - "hour": "hour", - "minute": "minute", - "monitorDeleted": "Monitor deleted successfully", - "monitorPaused": "Monitor paused successfully", - "monitorResumed": "Monitor resumed successfully", - "name": "Name" + } } From 1888ee04786899587ee5d65ab4dc10eb0d6f1dbf Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 13 Feb 2026 21:19:55 +0000 Subject: [PATCH 30/58] remove unused monitor import --- client/src/Utils/MonitorUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Utils/MonitorUtils.ts b/client/src/Utils/MonitorUtils.ts index be4595090..02c291efc 100644 --- a/client/src/Utils/MonitorUtils.ts +++ b/client/src/Utils/MonitorUtils.ts @@ -1,4 +1,4 @@ -import type { Monitor, MonitorStatus, MonitorType } from "@/Types/Monitor"; +import type { MonitorStatus, MonitorType } from "@/Types/Monitor"; import type { PaletteKey } from "@/Utils/Theme/v2Theme"; import type { ValueType } from "@/Components/v2/design-elements/StatusLabel"; From 2f6dbe9a3ad9cb10374da442edae1a11aca71bd7 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 13 Feb 2026 23:56:35 +0000 Subject: [PATCH 31/58] update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2299e795a..f6e292bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ .VSCodeCounter *.sh mongo -node_modules/ \ No newline at end of file +node_modules/ +docs/architecture \ No newline at end of file From 86fd535eafc81e3a39e99f8bef7c11c940508a5f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 00:08:28 +0000 Subject: [PATCH 32/58] routes to TS --- client/src/Pages/NotFound/index.tsx | 4 ++-- client/src/Routes/{index.jsx => index.tsx} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename client/src/Routes/{index.jsx => index.tsx} (98%) diff --git a/client/src/Pages/NotFound/index.tsx b/client/src/Pages/NotFound/index.tsx index 709f808be..868a1573a 100644 --- a/client/src/Pages/NotFound/index.tsx +++ b/client/src/Pages/NotFound/index.tsx @@ -9,8 +9,8 @@ import { useTheme } from "@mui/material"; import { useTranslation } from "react-i18next"; interface NotFoundProps { - title: string; - desc: string; + title?: string; + desc?: string; } const NotFoundPage = ({ title, desc }: NotFoundProps) => { diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.tsx similarity index 98% rename from client/src/Routes/index.jsx rename to client/src/Routes/index.tsx index 3b0b76fc6..e3c0b0667 100644 --- a/client/src/Routes/index.jsx +++ b/client/src/Routes/index.tsx @@ -3,6 +3,7 @@ import { ThemeProvider } from "@mui/material"; import { lightTheme, darkTheme } from "@/Utils/Theme/v2Theme"; import { useSelector } from "react-redux"; +import type { RootState } from "@/store"; import { Navigate, Route, Routes as LibRoutes } from "react-router"; import RootLayout from "@/Components/v2/layout/RootLayout"; import NotFound from "@/Pages/NotFound"; @@ -59,7 +60,7 @@ import { import CreateMonitor from "@/Pages/CreateMonitor"; const Routes = () => { - const mode = useSelector((state) => state.ui.mode); + const mode = useSelector((state: RootState) => state.ui.mode); const v2theme = mode === "light" ? lightTheme : darkTheme; return ( @@ -390,12 +391,11 @@ const Routes = () => { /> - + } From 002a82bb9a90c57e625da3b0ef78f4ada5868ff7 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 00:19:01 +0000 Subject: [PATCH 33/58] fix port input --- client/src/Pages/CreateMonitor/index.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/src/Pages/CreateMonitor/index.tsx b/client/src/Pages/CreateMonitor/index.tsx index e7ceb52b1..d7dde2a08 100644 --- a/client/src/Pages/CreateMonitor/index.tsx +++ b/client/src/Pages/CreateMonitor/index.tsx @@ -329,8 +329,11 @@ const CreateMonitorPage = () => { render={({ field, fieldState }) => ( field.onChange(Number(e.target.value) || 0)} + value={field.value === 0 ? "" : field.value} + onChange={(e) => { + const val = e.target.value; + field.onChange(val === "" ? 0 : Number(val)); + }} type="number" fieldLabel={t("pages.createMonitor.form.general.option.port.label")} placeholder={t( From c31973804803a06e98efba60d620f94bcf97b985 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 00:40:59 +0000 Subject: [PATCH 34/58] add config box for thresholds --- client/src/Pages/CreateMonitor/index.tsx | 108 +++++++++++++++++++++++ client/src/locales/en.json | 23 ++++- 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/client/src/Pages/CreateMonitor/index.tsx b/client/src/Pages/CreateMonitor/index.tsx index e7ceb52b1..76848d269 100644 --- a/client/src/Pages/CreateMonitor/index.tsx +++ b/client/src/Pages/CreateMonitor/index.tsx @@ -486,6 +486,114 @@ const CreateMonitorPage = () => { } /> + {/* Alert Thresholds - only for hardware type */} + {generalSettingsConfig.showSecret && ( + + ( + { + const val = e.target.value; + field.onChange(val === "" ? 0 : Number(val)); + }} + type="number" + fieldLabel={t( + "pages.createMonitor.form.thresholds.option.cpuThreshold.label" + )} + placeholder={t( + "pages.createMonitor.form.thresholds.option.cpuThreshold.placeholder" + )} + fullWidth + error={!!fieldState.error} + helperText={fieldState.error?.message ?? ""} + /> + )} + /> + ( + { + const val = e.target.value; + field.onChange(val === "" ? 0 : Number(val)); + }} + type="number" + fieldLabel={t( + "pages.createMonitor.form.thresholds.option.memoryThreshold.label" + )} + placeholder={t( + "pages.createMonitor.form.thresholds.option.memoryThreshold.placeholder" + )} + fullWidth + error={!!fieldState.error} + helperText={fieldState.error?.message ?? ""} + /> + )} + /> + ( + { + const val = e.target.value; + field.onChange(val === "" ? 0 : Number(val)); + }} + type="number" + fieldLabel={t( + "pages.createMonitor.form.thresholds.option.diskThreshold.label" + )} + placeholder={t( + "pages.createMonitor.form.thresholds.option.diskThreshold.placeholder" + )} + fullWidth + error={!!fieldState.error} + helperText={fieldState.error?.message ?? ""} + /> + )} + /> + ( + { + const val = e.target.value; + field.onChange(val === "" ? 0 : Number(val)); + }} + type="number" + fieldLabel={t( + "pages.createMonitor.form.thresholds.option.tempThreshold.label" + )} + placeholder={t( + "pages.createMonitor.form.thresholds.option.tempThreshold.placeholder" + )} + fullWidth + error={!!fieldState.error} + helperText={fieldState.error?.message ?? ""} + /> + )} + /> + + } + /> + )} + Date: Sat, 14 Feb 2026 01:02:15 +0000 Subject: [PATCH 35/58] use sliderwithlabels --- client/src/Pages/CreateMonitor/index.tsx | 88 +++++++++--------------- 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/client/src/Pages/CreateMonitor/index.tsx b/client/src/Pages/CreateMonitor/index.tsx index 76848d269..67cc512f8 100644 --- a/client/src/Pages/CreateMonitor/index.tsx +++ b/client/src/Pages/CreateMonitor/index.tsx @@ -496,96 +496,72 @@ const CreateMonitorPage = () => { ( - ( + { - const val = e.target.value; - field.onChange(val === "" ? 0 : Number(val)); - }} - type="number" + sliderMaxWidth={{ xs: "100%", md: "50%" }} fieldLabel={t( "pages.createMonitor.form.thresholds.option.cpuThreshold.label" )} - placeholder={t( - "pages.createMonitor.form.thresholds.option.cpuThreshold.placeholder" - )} - fullWidth - error={!!fieldState.error} - helperText={fieldState.error?.message ?? ""} + min={0} + max={100} + step={1} + valueLabelDisplay="auto" + valueLabelFormat={(value) => `${value}%`} /> )} /> ( - ( + { - const val = e.target.value; - field.onChange(val === "" ? 0 : Number(val)); - }} - type="number" + sliderMaxWidth={{ xs: "100%", md: "50%" }} fieldLabel={t( "pages.createMonitor.form.thresholds.option.memoryThreshold.label" )} - placeholder={t( - "pages.createMonitor.form.thresholds.option.memoryThreshold.placeholder" - )} - fullWidth - error={!!fieldState.error} - helperText={fieldState.error?.message ?? ""} + min={0} + max={100} + step={1} + valueLabelDisplay="auto" + valueLabelFormat={(value) => `${value}%`} /> )} /> ( - ( + { - const val = e.target.value; - field.onChange(val === "" ? 0 : Number(val)); - }} - type="number" + sliderMaxWidth={{ xs: "100%", md: "50%" }} fieldLabel={t( "pages.createMonitor.form.thresholds.option.diskThreshold.label" )} - placeholder={t( - "pages.createMonitor.form.thresholds.option.diskThreshold.placeholder" - )} - fullWidth - error={!!fieldState.error} - helperText={fieldState.error?.message ?? ""} + min={0} + max={100} + step={1} + valueLabelDisplay="auto" + valueLabelFormat={(value) => `${value}%`} /> )} /> ( - ( + { - const val = e.target.value; - field.onChange(val === "" ? 0 : Number(val)); - }} - type="number" + sliderMaxWidth={{ xs: "100%", md: "50%" }} fieldLabel={t( "pages.createMonitor.form.thresholds.option.tempThreshold.label" )} - placeholder={t( - "pages.createMonitor.form.thresholds.option.tempThreshold.placeholder" - )} - fullWidth - error={!!fieldState.error} - helperText={fieldState.error?.message ?? ""} + min={0} + max={100} + step={1} + valueLabelDisplay="auto" + valueLabelFormat={(value) => `${value}°C`} /> )} /> From f694917dd40524001ddd55bd37ca7e5a573c47e1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 01:07:46 +0000 Subject: [PATCH 36/58] remove unused --- client/src/locales/en.json | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/client/src/locales/en.json b/client/src/locales/en.json index c199e3151..8e18d8e2a 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -526,20 +526,16 @@ "description": "Define the thresholds at which alerts should be triggered for this hardware monitor.", "option": { "cpuThreshold": { - "label": "CPU alert threshold (%)", - "placeholder": "80" + "label": "CPU alert threshold (%)" }, "memoryThreshold": { - "label": "Memory alert threshold (%)", - "placeholder": "80" + "label": "Memory alert threshold (%)" }, "diskThreshold": { - "label": "Disk alert threshold (%)", - "placeholder": "80" + "label": "Disk alert threshold (%)" }, "tempThreshold": { - "label": "Temperature alert threshold (°C)", - "placeholder": "80" + "label": "Temperature alert threshold (°C)" } } } From 2430bbeebba522f309699ba89e9736e0a1dbc6b9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 01:15:12 +0000 Subject: [PATCH 37/58] remove slider hover --- client/src/Components/v2/inputs/Slider.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/Components/v2/inputs/Slider.tsx b/client/src/Components/v2/inputs/Slider.tsx index 97a16ac2c..1bdb57cb3 100644 --- a/client/src/Components/v2/inputs/Slider.tsx +++ b/client/src/Components/v2/inputs/Slider.tsx @@ -39,9 +39,14 @@ export const SliderInput = forwardRef( opacity: 1, }, "& .MuiSlider-thumb": { + height: 15, + width: 15, backgroundColor: "#fff", "&:hover, &.Mui-focusVisible": { - boxShadow: `0 0 0 8px ${theme.palette.primary.main}20`, + boxShadow: "none", + }, + "&:active": { + boxShadow: "none", }, }, "& .MuiSlider-valueLabel": { From 111b68b8df7a20ec5bd0ed08c9d22fd7567f672e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 01:21:02 +0000 Subject: [PATCH 38/58] revert slider size change --- client/src/Components/v2/inputs/Slider.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/src/Components/v2/inputs/Slider.tsx b/client/src/Components/v2/inputs/Slider.tsx index 1bdb57cb3..83037ab54 100644 --- a/client/src/Components/v2/inputs/Slider.tsx +++ b/client/src/Components/v2/inputs/Slider.tsx @@ -39,8 +39,6 @@ export const SliderInput = forwardRef( opacity: 1, }, "& .MuiSlider-thumb": { - height: 15, - width: 15, backgroundColor: "#fff", "&:hover, &.Mui-focusVisible": { boxShadow: "none", From 4a73170583dc642d0bef3f4f242f9dd156df6357 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 21:05:31 +0000 Subject: [PATCH 39/58] initial commit --- .../SuperSimpleQueueHelper.ts | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 6c9e9264a..e9439feef 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -2,9 +2,24 @@ const SERVICE_NAME = "JobQueueHelper"; import type { Monitor } from "@/types/monitor.js"; import { AppError } from "@/utils/AppError.js"; import { INetworkService, INotificationsService, IStatusService } from "@/service/index.js"; +import type { StatusChangeResult, MonitorStatusResponse, HardwareStatusPayload, MonitorStatus } from "@/types/index.js"; import IncidentService from "@/service/business/incidentService.js"; import { IMaintenanceWindowsRepository, IMonitorsRepository } from "@/repositories/index.js"; +export interface MonitorActionDecision { + shouldCreateIncident: boolean; + shouldResolveIncident: boolean; + shouldSendNotification: boolean; + incidentReason: "status_down" | "threshold_breach" | null; + notificationReason: "status_change" | "threshold_breach" | null; + thresholdBreaches?: { + cpu?: boolean; + memory?: boolean; + disk?: boolean; + temp?: boolean; + }; +} + class SuperSimpleQueueHelper { static SERVICE_NAME = SERVICE_NAME; @@ -166,6 +181,126 @@ class SuperSimpleQueueHelper { }, false); return maintenanceWindowIsActive; } + + /** + * Evaluates what actions should be taken based on monitor status and hardware thresholds. + * This is a pure decision function that returns what should happen without executing anything. + * + * @param statusChangeResult - Result from statusService.updateMonitorStatus() + * @param networkResponse - Network response containing payload data + * @returns Decision object indicating what actions to take + */ + private evaluateMonitorAction(statusChangeResult: StatusChangeResult, networkResponse: MonitorStatusResponse): MonitorActionDecision { + const { monitor, statusChanged, prevStatus } = statusChangeResult; + + // Initialize result + const decision: MonitorActionDecision = { + shouldCreateIncident: false, + shouldResolveIncident: false, + shouldSendNotification: false, + incidentReason: null, + notificationReason: null, + }; + + // CASE 1: Non-hardware monitors (http, ping, port, docker, pagespeed, game) + if (monitor.type !== "hardware") { + // Only act on status changes + if (statusChanged) { + if (monitor.status === "down") { + decision.shouldCreateIncident = true; + decision.shouldSendNotification = true; + decision.incidentReason = "status_down"; + decision.notificationReason = "status_change"; + } else if (monitor.status === "up" && prevStatus === "down") { + decision.shouldResolveIncident = true; + decision.shouldSendNotification = true; + decision.notificationReason = "status_change"; + } + } + return decision; + } + + // CASE 2: Hardware monitors + const payload = networkResponse.payload as HardwareStatusPayload; + const metrics = payload?.data; + + if (!metrics) { + return decision; // No metrics, can't evaluate + } + + // Check if thresholds exist + const thresholds = monitor.thresholds || {}; + const hasThresholds = + thresholds.usage_cpu !== undefined || + thresholds.usage_memory !== undefined || + thresholds.usage_disk !== undefined || + thresholds.usage_temperature !== undefined; + + // Evaluate threshold breaches + const breaches = { + cpu: false, + memory: false, + disk: false, + temp: false, + }; + + if (hasThresholds) { + // CPU check + if (thresholds.usage_cpu !== undefined) { + const cpuUsage = metrics.cpu?.usage_percent ?? -1; + breaches.cpu = cpuUsage !== -1 && cpuUsage > thresholds.usage_cpu; + } + + // Memory check + if (thresholds.usage_memory !== undefined) { + const memoryUsage = metrics.memory?.usage_percent ?? -1; + breaches.memory = memoryUsage !== -1 && memoryUsage > thresholds.usage_memory; + } + + // Disk check + if (thresholds.usage_disk !== undefined) { + breaches.disk = metrics.disk?.some((d: any) => typeof d?.usage_percent === "number" && d.usage_percent > thresholds.usage_disk!) ?? false; + } + + // Temperature check (alert if ANY sensor exceeds threshold) + if (thresholds.usage_temperature !== undefined) { + const temps = metrics.cpu?.temperature ?? []; + breaches.temp = temps.some((temp: number) => temp > thresholds.usage_temperature!); + } + } + + const anyThresholdBreached = Object.values(breaches).some((b) => b); + + // Check if countdown has reached zero for any threshold + const shouldNotifyThreshold = + (breaches.cpu && (monitor.cpuAlertThreshold ?? monitor.alertThreshold) <= 0) || + (breaches.memory && (monitor.memoryAlertThreshold ?? monitor.alertThreshold) <= 0) || + (breaches.disk && (monitor.diskAlertThreshold ?? monitor.alertThreshold) <= 0) || + (breaches.temp && (monitor.tempAlertThreshold ?? monitor.alertThreshold) <= 0); + + // Decision logic for hardware + if (statusChanged && monitor.status === "down") { + // Hardware service is DOWN (unreachable) + decision.shouldCreateIncident = true; + decision.shouldSendNotification = true; + decision.incidentReason = "status_down"; + decision.notificationReason = "status_change"; + } else if (statusChanged && monitor.status === "up" && prevStatus === "down") { + // Hardware service recovered + decision.shouldResolveIncident = true; + decision.shouldSendNotification = true; + decision.notificationReason = "status_change"; + } else if (anyThresholdBreached && shouldNotifyThreshold) { + // Threshold breach alert (service is UP but metrics are high) + decision.shouldCreateIncident = true; + decision.shouldSendNotification = true; + decision.incidentReason = "threshold_breach"; + decision.notificationReason = "threshold_breach"; + decision.thresholdBreaches = breaches; + } + + return decision; + } } export default SuperSimpleQueueHelper; From a7b0ce4d8ffd5d7d7cded37a1b0c9c4c91b91578 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 21:21:18 +0000 Subject: [PATCH 40/58] remove thresholds --- client/src/Types/Monitor.ts | 8 ---- server/src/db/models/Monitor.ts | 16 +------ .../monitors/MongoMonitorsRepository.ts | 2 - .../SuperSimpleQueueHelper.ts | 44 +++++++++---------- .../notificationProviders/utils.ts | 12 +++-- .../infrastructure/notificationsService.ts | 9 +++- server/src/types/monitor.ts | 8 ---- 7 files changed, 36 insertions(+), 63 deletions(-) diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index ea6f4d019..2f1c1838d 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -21,13 +21,6 @@ export const MonitorStatuses = [ ] as const; export type MonitorStatus = (typeof MonitorStatuses)[number]; -export interface MonitorThresholds { - usage_cpu?: number; - usage_memory?: number; - usage_disk?: number; - usage_temperature?: number; -} - export type MonitorMatchMethod = "equal" | "include" | "regex" | ""; export interface Monitor { @@ -53,7 +46,6 @@ export interface Monitor { uptimePercentage?: number; notifications: string[]; secret?: string; - thresholds?: MonitorThresholds; alertThreshold: number; cpuAlertThreshold: number; memoryAlertThreshold: number; diff --git a/server/src/db/models/Monitor.ts b/server/src/db/models/Monitor.ts index 9111ce47f..bb3108ed3 100644 --- a/server/src/db/models/Monitor.ts +++ b/server/src/db/models/Monitor.ts @@ -1,5 +1,5 @@ import { Schema, model, Types, type UpdateQuery } from "mongoose"; -import type { Monitor, MonitorMatchMethod, MonitorThresholds, CheckSnapshot } from "@/types/monitor.js"; +import type { Monitor, MonitorMatchMethod, CheckSnapshot } from "@/types/monitor.js"; import { MonitorTypes, MonitorStatuses } from "@/types/monitor.js"; type CheckSnapshotDocument = Omit & { createdAt: Date }; @@ -13,7 +13,6 @@ type MonitorDocumentBase = Omit< notifications: Types.ObjectId[]; selectedDisks: string[]; matchMethod?: MonitorMatchMethod; - thresholds?: MonitorThresholds; }; interface MonitorDocument extends MonitorDocumentBase { @@ -24,16 +23,6 @@ interface MonitorDocument extends MonitorDocumentBase { updatedAt: Date; } -const thresholdsSchema = new Schema( - { - usage_cpu: { type: Number }, - usage_memory: { type: Number }, - usage_disk: { type: Number }, - usage_temperature: { type: Number }, - }, - { _id: false } -); - const checkSnapshotSchema = new Schema( { id: { type: String, required: true }, @@ -132,9 +121,6 @@ const MonitorSchema = new Schema( secret: { type: String, }, - thresholds: { - type: thresholdsSchema, - }, alertThreshold: { type: Number, default: 5, diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index 65d93421e..7390d0e0e 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -317,7 +317,6 @@ class MongoMonitorsRepository implements IMonitorsRepository { uptimePercentage: doc.uptimePercentage ?? undefined, notifications: notificationIds, secret: doc.secret ?? undefined, - thresholds: doc.thresholds ?? undefined, alertThreshold: doc.alertThreshold, cpuAlertThreshold: doc.cpuAlertThreshold, memoryAlertThreshold: doc.memoryAlertThreshold, @@ -370,7 +369,6 @@ class MongoMonitorsRepository implements IMonitorsRepository { uptimePercentage: doc.uptimePercentage ?? undefined, notifications: notificationIds, secret: doc.secret ?? undefined, - thresholds: doc.thresholds ?? undefined, alertThreshold: doc.alertThreshold, cpuAlertThreshold: doc.cpuAlertThreshold, memoryAlertThreshold: doc.memoryAlertThreshold, diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index e9439feef..0b143450c 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -182,14 +182,6 @@ class SuperSimpleQueueHelper { return maintenanceWindowIsActive; } - /** - * Evaluates what actions should be taken based on monitor status and hardware thresholds. - * This is a pure decision function that returns what should happen without executing anything. - * - * @param statusChangeResult - Result from statusService.updateMonitorStatus() - * @param networkResponse - Network response containing payload data - * @returns Decision object indicating what actions to take - */ private evaluateMonitorAction(statusChangeResult: StatusChangeResult, networkResponse: MonitorStatusResponse): MonitorActionDecision { const { monitor, statusChanged, prevStatus } = statusChangeResult; @@ -202,10 +194,10 @@ class SuperSimpleQueueHelper { notificationReason: null, }; - // CASE 1: Non-hardware monitors (http, ping, port, docker, pagespeed, game) + // CASE 1: Non-hardware if (monitor.type !== "hardware") { - // Only act on status changes if (statusChanged) { + // This is the current state of the monitor AFTER the most recent check if (monitor.status === "down") { decision.shouldCreateIncident = true; decision.shouldSendNotification = true; @@ -220,7 +212,7 @@ class SuperSimpleQueueHelper { return decision; } - // CASE 2: Hardware monitors + // CASE 2: Hardware const payload = networkResponse.payload as HardwareStatusPayload; const metrics = payload?.data; @@ -229,12 +221,11 @@ class SuperSimpleQueueHelper { } // Check if thresholds exist - const thresholds = monitor.thresholds || {}; const hasThresholds = - thresholds.usage_cpu !== undefined || - thresholds.usage_memory !== undefined || - thresholds.usage_disk !== undefined || - thresholds.usage_temperature !== undefined; + monitor.cpuAlertThreshold !== undefined || + monitor.memoryAlertThreshold !== undefined || + monitor.diskAlertThreshold !== undefined || + monitor.tempAlertThreshold !== undefined; // Evaluate threshold breaches const breaches = { @@ -246,26 +237,31 @@ class SuperSimpleQueueHelper { if (hasThresholds) { // CPU check - if (thresholds.usage_cpu !== undefined) { + if (monitor.cpuAlertThreshold !== undefined) { const cpuUsage = metrics.cpu?.usage_percent ?? -1; - breaches.cpu = cpuUsage !== -1 && cpuUsage > thresholds.usage_cpu; + // Convert threshold from percentage (0-100) to decimal (0-1) for comparison + breaches.cpu = cpuUsage !== -1 && cpuUsage > monitor.cpuAlertThreshold / 100; } // Memory check - if (thresholds.usage_memory !== undefined) { + if (monitor.memoryAlertThreshold !== undefined) { const memoryUsage = metrics.memory?.usage_percent ?? -1; - breaches.memory = memoryUsage !== -1 && memoryUsage > thresholds.usage_memory; + // Convert threshold from percentage (0-100) to decimal (0-1) for comparison + breaches.memory = memoryUsage !== -1 && memoryUsage > monitor.memoryAlertThreshold / 100; } // Disk check - if (thresholds.usage_disk !== undefined) { - breaches.disk = metrics.disk?.some((d: any) => typeof d?.usage_percent === "number" && d.usage_percent > thresholds.usage_disk!) ?? false; + if (monitor.diskAlertThreshold !== undefined) { + // Convert threshold from percentage (0-100) to decimal (0-1) for comparison + breaches.disk = + metrics.disk?.some((d: any) => typeof d?.usage_percent === "number" && d.usage_percent > monitor.diskAlertThreshold / 100) ?? false; } // Temperature check (alert if ANY sensor exceeds threshold) - if (thresholds.usage_temperature !== undefined) { + if (monitor.tempAlertThreshold !== undefined) { const temps = metrics.cpu?.temperature ?? []; - breaches.temp = temps.some((temp: number) => temp > thresholds.usage_temperature!); + // Temperature threshold is in Celsius, compare directly + breaches.temp = temps.some((temp: number) => temp > monitor.tempAlertThreshold); } } diff --git a/server/src/service/infrastructure/notificationProviders/utils.ts b/server/src/service/infrastructure/notificationProviders/utils.ts index 2fe22e834..ac964d93f 100644 --- a/server/src/service/infrastructure/notificationProviders/utils.ts +++ b/server/src/service/infrastructure/notificationProviders/utils.ts @@ -23,8 +23,10 @@ export const buildHardwareAlerts = ( monitor: Monitor, networkResponse: MonitorStatusResponse ): { alertsToSend: string[]; discordPayload: any } => { - const thresholds = monitor.thresholds || {}; - const { usage_cpu: cpuThreshold = -1, usage_memory: memoryThreshold = -1, usage_disk: diskThreshold = -1 } = thresholds; + // Thresholds are stored as percentages (0-100), convert to decimal (0-1) for comparison + const cpuThreshold = monitor.cpuAlertThreshold !== undefined ? monitor.cpuAlertThreshold / 100 : -1; + const memoryThreshold = monitor.memoryAlertThreshold !== undefined ? monitor.memoryAlertThreshold / 100 : -1; + const diskThreshold = monitor.diskAlertThreshold !== undefined ? monitor.diskAlertThreshold / 100 : -1; const payload = networkResponse?.payload as HardwareStatusPayload; const metrics = payload.data || {}; @@ -124,8 +126,10 @@ export const buildHardwareWebhookBody = (alerts: string[], monitor: Monitor): st }; export const shouldSendHardwareAlert = (monitor: Monitor, networkResponse: MonitorStatusResponse): boolean => { - const thresholds = monitor.thresholds || {}; - const { usage_cpu: cpuThreshold = -1, usage_memory: memoryThreshold = -1, usage_disk: diskThreshold = -1 } = thresholds; + // Thresholds are stored as percentages (0-100), convert to decimal (0-1) for comparison + const cpuThreshold = monitor.cpuAlertThreshold !== undefined ? monitor.cpuAlertThreshold / 100 : -1; + const memoryThreshold = monitor.memoryAlertThreshold !== undefined ? monitor.memoryAlertThreshold / 100 : -1; + const diskThreshold = monitor.diskAlertThreshold !== undefined ? monitor.diskAlertThreshold / 100 : -1; const payload = networkResponse?.payload as HardwareStatusPayload; const metrics = payload.data || {}; diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index 531014a7a..b2ae59b7c 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -239,9 +239,14 @@ export class NotificationsService implements INotificationsService { // Deal with hardware thresholds if (type === "hardware") { - const thresholds = monitor.thresholds; + // Check if any thresholds are set + const hasThresholds = + monitor.cpuAlertThreshold !== undefined || + monitor.memoryAlertThreshold !== undefined || + monitor.diskAlertThreshold !== undefined || + monitor.tempAlertThreshold !== undefined; - if (thresholds === undefined) return false; // No thresholds set, we're done + if (!hasThresholds) return false; // No thresholds set, we're done const metrics = payload?.data ?? null; if (metrics === null) return false; // No metrics, we're done diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index 384e14fe0..83a207e2d 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -7,13 +7,6 @@ export type MonitorType = (typeof MonitorTypes)[number]; export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance"] as const; export type MonitorStatus = (typeof MonitorStatuses)[number]; -export interface MonitorThresholds { - usage_cpu?: number; - usage_memory?: number; - usage_disk?: number; - usage_temperature?: number; -} - export type MonitorMatchMethod = "equal" | "include" | "regex" | ""; export interface Monitor { @@ -39,7 +32,6 @@ export interface Monitor { uptimePercentage?: number; notifications: string[]; secret?: string; - thresholds?: MonitorThresholds; alertThreshold: number; cpuAlertThreshold: number; memoryAlertThreshold: number; From 2fb6cb0b6f3f614dc0fb1c860a84ca9364858676 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 21:29:30 +0000 Subject: [PATCH 41/58] remove alertThreshold --- client/src/Hooks/useMonitorForm.ts | 8 ++-- client/src/Types/Monitor.ts | 1 - server/src/db/models/Monitor.ts | 47 ++----------------- .../monitors/MongoMonitorsRepository.ts | 2 - .../SuperSimpleQueueHelper.ts | 8 ++-- .../notificationProviders/utils.ts | 10 ++-- server/src/types/monitor.ts | 1 - 7 files changed, 17 insertions(+), 60 deletions(-) diff --git a/client/src/Hooks/useMonitorForm.ts b/client/src/Hooks/useMonitorForm.ts index 153cf9f19..633fcb5c9 100644 --- a/client/src/Hooks/useMonitorForm.ts +++ b/client/src/Hooks/useMonitorForm.ts @@ -83,10 +83,10 @@ export const useMonitorForm = ({ type: "hardware", url: data?.url || "", secret: data?.secret || "", - cpuAlertThreshold: data?.cpuAlertThreshold ?? 80, - memoryAlertThreshold: data?.memoryAlertThreshold ?? 80, - diskAlertThreshold: data?.diskAlertThreshold ?? 80, - tempAlertThreshold: data?.tempAlertThreshold ?? 80, + cpuAlertThreshold: data?.cpuAlertThreshold ?? 100, + memoryAlertThreshold: data?.memoryAlertThreshold ?? 100, + diskAlertThreshold: data?.diskAlertThreshold ?? 100, + tempAlertThreshold: data?.tempAlertThreshold ?? 100, selectedDisks: data?.selectedDisks || [], }; break; diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index 2f1c1838d..fdd66b671 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -46,7 +46,6 @@ export interface Monitor { uptimePercentage?: number; notifications: string[]; secret?: string; - alertThreshold: number; cpuAlertThreshold: number; memoryAlertThreshold: number; diskAlertThreshold: number; diff --git a/server/src/db/models/Monitor.ts b/server/src/db/models/Monitor.ts index bb3108ed3..673872fba 100644 --- a/server/src/db/models/Monitor.ts +++ b/server/src/db/models/Monitor.ts @@ -121,33 +121,21 @@ const MonitorSchema = new Schema( secret: { type: String, }, - alertThreshold: { - type: Number, - default: 5, - }, cpuAlertThreshold: { type: Number, - default: function () { - return this.alertThreshold; - }, + default: 100, }, memoryAlertThreshold: { type: Number, - default: function () { - return this.alertThreshold; - }, + default: 100, }, diskAlertThreshold: { type: Number, - default: function () { - return this.alertThreshold; - }, + default: 100, }, tempAlertThreshold: { type: Number, - default: function () { - return this.alertThreshold; - }, + default: 100, }, selectedDisks: { type: [String], @@ -175,33 +163,6 @@ const MonitorSchema = new Schema( } ); -MonitorSchema.pre("save", function (next) { - if (!this.cpuAlertThreshold || this.isModified("alertThreshold")) { - this.cpuAlertThreshold = this.alertThreshold; - } - if (!this.memoryAlertThreshold || this.isModified("alertThreshold")) { - this.memoryAlertThreshold = this.alertThreshold; - } - if (!this.diskAlertThreshold || this.isModified("alertThreshold")) { - this.diskAlertThreshold = this.alertThreshold; - } - if (!this.tempAlertThreshold || this.isModified("alertThreshold")) { - this.tempAlertThreshold = this.alertThreshold; - } - next(); -}); - -MonitorSchema.pre("findOneAndUpdate", function (next) { - const update = this.getUpdate() as UpdateQuery | null; - if (update && !Array.isArray(update) && update.alertThreshold !== undefined) { - update.cpuAlertThreshold = update.alertThreshold; - update.memoryAlertThreshold = update.alertThreshold; - update.diskAlertThreshold = update.alertThreshold; - update.tempAlertThreshold = update.alertThreshold; - } - next(); -}); - MonitorSchema.index({ teamId: 1, type: 1 }); const MonitorModel = model("Monitor", MonitorSchema); diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index 7390d0e0e..71d4a2a41 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -317,7 +317,6 @@ class MongoMonitorsRepository implements IMonitorsRepository { uptimePercentage: doc.uptimePercentage ?? undefined, notifications: notificationIds, secret: doc.secret ?? undefined, - alertThreshold: doc.alertThreshold, cpuAlertThreshold: doc.cpuAlertThreshold, memoryAlertThreshold: doc.memoryAlertThreshold, diskAlertThreshold: doc.diskAlertThreshold, @@ -369,7 +368,6 @@ class MongoMonitorsRepository implements IMonitorsRepository { uptimePercentage: doc.uptimePercentage ?? undefined, notifications: notificationIds, secret: doc.secret ?? undefined, - alertThreshold: doc.alertThreshold, cpuAlertThreshold: doc.cpuAlertThreshold, memoryAlertThreshold: doc.memoryAlertThreshold, diskAlertThreshold: doc.diskAlertThreshold, diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 0b143450c..85e54f793 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -269,10 +269,10 @@ class SuperSimpleQueueHelper { // Check if countdown has reached zero for any threshold const shouldNotifyThreshold = - (breaches.cpu && (monitor.cpuAlertThreshold ?? monitor.alertThreshold) <= 0) || - (breaches.memory && (monitor.memoryAlertThreshold ?? monitor.alertThreshold) <= 0) || - (breaches.disk && (monitor.diskAlertThreshold ?? monitor.alertThreshold) <= 0) || - (breaches.temp && (monitor.tempAlertThreshold ?? monitor.alertThreshold) <= 0); + (breaches.cpu && (monitor.cpuAlertThreshold ?? 100) <= 0) || + (breaches.memory && (monitor.memoryAlertThreshold ?? 100) <= 0) || + (breaches.disk && (monitor.diskAlertThreshold ?? 100) <= 0) || + (breaches.temp && (monitor.tempAlertThreshold ?? 100) <= 0); // Decision logic for hardware if (statusChanged && monitor.status === "down") { diff --git a/server/src/service/infrastructure/notificationProviders/utils.ts b/server/src/service/infrastructure/notificationProviders/utils.ts index ac964d93f..284855846 100644 --- a/server/src/service/infrastructure/notificationProviders/utils.ts +++ b/server/src/service/infrastructure/notificationProviders/utils.ts @@ -88,12 +88,12 @@ export const buildHardwareAlerts = ( const thresholdKey = alertThresholdKeyMap[type]; // Iterate over each alert type to see if any need to be decremented if (alerts[type] === true) { - const nextValue = ((monitor[thresholdKey] ?? monitor.alertThreshold) as number) - 1; + const nextValue = ((monitor[thresholdKey] ?? 100) as number) - 1; monitor[thresholdKey] = nextValue; // Decrement threshold if an alert is triggered if (monitor[thresholdKey] <= 0) { // If threshold drops below 0, reset and send notification - monitor[thresholdKey] = monitor.alertThreshold; + monitor[thresholdKey] = 100; const formatAlert = { cpu: () => `Your current CPU usage (${(cpuUsage * 100).toFixed(0)}%) is above your threshold (${(cpuThreshold * 100).toFixed(0)}%)`, @@ -136,17 +136,17 @@ export const shouldSendHardwareAlert = (monitor: Monitor, networkResponse: Monit const { cpu: { usage_percent: cpuUsage = -1 } = {}, memory: { usage_percent: memoryUsage = -1 } = {}, disk = [] } = metrics; const cpuBreach = cpuThreshold !== -1 && cpuUsage > cpuThreshold; - if (cpuBreach && ((monitor.cpuAlertThreshold ?? monitor.alertThreshold) as number) - 1 <= 0) { + if (cpuBreach && ((monitor.cpuAlertThreshold ?? 100) as number) - 1 <= 0) { return true; } const memoryBreach = memoryThreshold !== -1 && memoryUsage > memoryThreshold; - if (memoryBreach && ((monitor.memoryAlertThreshold ?? monitor.alertThreshold) as number) - 1 <= 0) { + if (memoryBreach && ((monitor.memoryAlertThreshold ?? 100) as number) - 1 <= 0) { return true; } const diskBreach = disk?.some((d) => diskThreshold !== -1 && typeof d?.usage_percent === "number" && d?.usage_percent > diskThreshold); - if (diskBreach && ((monitor.diskAlertThreshold ?? monitor.alertThreshold) as number) - 1 <= 0) { + if (diskBreach && ((monitor.diskAlertThreshold ?? 100) as number) - 1 <= 0) { return true; } diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index 83a207e2d..d92b351a9 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -32,7 +32,6 @@ export interface Monitor { uptimePercentage?: number; notifications: string[]; secret?: string; - alertThreshold: number; cpuAlertThreshold: number; memoryAlertThreshold: number; diskAlertThreshold: number; From 97ace1e05856da2fdf4473a4d0690d9cd3987801 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 21:38:00 +0000 Subject: [PATCH 42/58] remove unused checks --- .../SuperSimpleQueueHelper.ts | 69 +++++++------------ .../notificationProviders/utils.ts | 8 +-- 2 files changed, 28 insertions(+), 49 deletions(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 85e54f793..ec8a792f2 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -220,59 +220,38 @@ class SuperSimpleQueueHelper { return decision; // No metrics, can't evaluate } - // Check if thresholds exist - const hasThresholds = - monitor.cpuAlertThreshold !== undefined || - monitor.memoryAlertThreshold !== undefined || - monitor.diskAlertThreshold !== undefined || - monitor.tempAlertThreshold !== undefined; - // Evaluate threshold breaches + // CPU check + const cpuUsage = metrics.cpu?.usage_percent ?? -1; + const cpuBreach = cpuUsage !== -1 && cpuUsage > monitor.cpuAlertThreshold / 100; + + // Memory check + const memoryUsage = metrics.memory?.usage_percent ?? -1; + const memoryBreach = memoryUsage !== -1 && memoryUsage > monitor.memoryAlertThreshold / 100; + + // Disk check + const diskBreach = + metrics.disk?.some((d: any) => typeof d?.usage_percent === "number" && d.usage_percent > monitor.diskAlertThreshold / 100) ?? false; + + // Temperature check (alert if ANY sensor exceeds threshold) + const temps = metrics.cpu?.temperature ?? []; + const tempBreach = temps.some((temp: number) => temp > monitor.tempAlertThreshold); + const breaches = { - cpu: false, - memory: false, - disk: false, - temp: false, + cpu: cpuBreach, + memory: memoryBreach, + disk: diskBreach, + temp: tempBreach, }; - if (hasThresholds) { - // CPU check - if (monitor.cpuAlertThreshold !== undefined) { - const cpuUsage = metrics.cpu?.usage_percent ?? -1; - // Convert threshold from percentage (0-100) to decimal (0-1) for comparison - breaches.cpu = cpuUsage !== -1 && cpuUsage > monitor.cpuAlertThreshold / 100; - } - - // Memory check - if (monitor.memoryAlertThreshold !== undefined) { - const memoryUsage = metrics.memory?.usage_percent ?? -1; - // Convert threshold from percentage (0-100) to decimal (0-1) for comparison - breaches.memory = memoryUsage !== -1 && memoryUsage > monitor.memoryAlertThreshold / 100; - } - - // Disk check - if (monitor.diskAlertThreshold !== undefined) { - // Convert threshold from percentage (0-100) to decimal (0-1) for comparison - breaches.disk = - metrics.disk?.some((d: any) => typeof d?.usage_percent === "number" && d.usage_percent > monitor.diskAlertThreshold / 100) ?? false; - } - - // Temperature check (alert if ANY sensor exceeds threshold) - if (monitor.tempAlertThreshold !== undefined) { - const temps = metrics.cpu?.temperature ?? []; - // Temperature threshold is in Celsius, compare directly - breaches.temp = temps.some((temp: number) => temp > monitor.tempAlertThreshold); - } - } - const anyThresholdBreached = Object.values(breaches).some((b) => b); // Check if countdown has reached zero for any threshold const shouldNotifyThreshold = - (breaches.cpu && (monitor.cpuAlertThreshold ?? 100) <= 0) || - (breaches.memory && (monitor.memoryAlertThreshold ?? 100) <= 0) || - (breaches.disk && (monitor.diskAlertThreshold ?? 100) <= 0) || - (breaches.temp && (monitor.tempAlertThreshold ?? 100) <= 0); + (breaches.cpu && monitor.cpuAlertThreshold <= 0) || + (breaches.memory && monitor.memoryAlertThreshold <= 0) || + (breaches.disk && monitor.diskAlertThreshold <= 0) || + (breaches.temp && monitor.tempAlertThreshold <= 0); // Decision logic for hardware if (statusChanged && monitor.status === "down") { diff --git a/server/src/service/infrastructure/notificationProviders/utils.ts b/server/src/service/infrastructure/notificationProviders/utils.ts index 284855846..ed9d0177c 100644 --- a/server/src/service/infrastructure/notificationProviders/utils.ts +++ b/server/src/service/infrastructure/notificationProviders/utils.ts @@ -88,7 +88,7 @@ export const buildHardwareAlerts = ( const thresholdKey = alertThresholdKeyMap[type]; // Iterate over each alert type to see if any need to be decremented if (alerts[type] === true) { - const nextValue = ((monitor[thresholdKey] ?? 100) as number) - 1; + const nextValue = monitor[thresholdKey] - 1; monitor[thresholdKey] = nextValue; // Decrement threshold if an alert is triggered if (monitor[thresholdKey] <= 0) { @@ -136,17 +136,17 @@ export const shouldSendHardwareAlert = (monitor: Monitor, networkResponse: Monit const { cpu: { usage_percent: cpuUsage = -1 } = {}, memory: { usage_percent: memoryUsage = -1 } = {}, disk = [] } = metrics; const cpuBreach = cpuThreshold !== -1 && cpuUsage > cpuThreshold; - if (cpuBreach && ((monitor.cpuAlertThreshold ?? 100) as number) - 1 <= 0) { + if (cpuBreach && monitor.cpuAlertThreshold - 1 <= 0) { return true; } const memoryBreach = memoryThreshold !== -1 && memoryUsage > memoryThreshold; - if (memoryBreach && ((monitor.memoryAlertThreshold ?? 100) as number) - 1 <= 0) { + if (memoryBreach && monitor.memoryAlertThreshold - 1 <= 0) { return true; } const diskBreach = disk?.some((d) => diskThreshold !== -1 && typeof d?.usage_percent === "number" && d?.usage_percent > diskThreshold); - if (diskBreach && ((monitor.diskAlertThreshold ?? 100) as number) - 1 <= 0) { + if (diskBreach && monitor.diskAlertThreshold - 1 <= 0) { return true; } From 9c467c763dfacb24b45397f1adb22d88c9468175 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 21:49:32 +0000 Subject: [PATCH 43/58] add threshold counters --- client/src/Types/Monitor.ts | 4 ++++ server/src/db/models/Monitor.ts | 16 ++++++++++++++++ .../monitors/MongoMonitorsRepository.ts | 8 ++++++++ server/src/types/monitor.ts | 4 ++++ 4 files changed, 32 insertions(+) diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index fdd66b671..0c7cea5bd 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -47,9 +47,13 @@ export interface Monitor { notifications: string[]; secret?: string; cpuAlertThreshold: number; + cpuAlertCounter: number; memoryAlertThreshold: number; + memoryAlertCounter: number; diskAlertThreshold: number; + diskAlertCounter: number; tempAlertThreshold: number; + tempAlertCounter: number; selectedDisks: string[]; gameId?: string; group: string | null; diff --git a/server/src/db/models/Monitor.ts b/server/src/db/models/Monitor.ts index 673872fba..a459cdf3e 100644 --- a/server/src/db/models/Monitor.ts +++ b/server/src/db/models/Monitor.ts @@ -125,18 +125,34 @@ const MonitorSchema = new Schema( type: Number, default: 100, }, + cpuAlertCounter: { + type: Number, + default: 5, + }, memoryAlertThreshold: { type: Number, default: 100, }, + memoryAlertCounter: { + type: Number, + default: 5, + }, diskAlertThreshold: { type: Number, default: 100, }, + diskAlertCounter: { + type: Number, + default: 5, + }, tempAlertThreshold: { type: Number, default: 100, }, + tempAlertCounter: { + type: Number, + default: 5, + }, selectedDisks: { type: [String], default: [], diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index 71d4a2a41..c942d749a 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -318,9 +318,13 @@ class MongoMonitorsRepository implements IMonitorsRepository { notifications: notificationIds, secret: doc.secret ?? undefined, cpuAlertThreshold: doc.cpuAlertThreshold, + cpuAlertCounter: doc.cpuAlertCounter, memoryAlertThreshold: doc.memoryAlertThreshold, + memoryAlertCounter: doc.memoryAlertCounter, diskAlertThreshold: doc.diskAlertThreshold, + diskAlertCounter: doc.diskAlertCounter, tempAlertThreshold: doc.tempAlertThreshold, + tempAlertCounter: doc.tempAlertCounter, selectedDisks: doc.selectedDisks ?? [], gameId: doc.gameId ?? undefined, group: doc.group ?? null, @@ -369,9 +373,13 @@ class MongoMonitorsRepository implements IMonitorsRepository { notifications: notificationIds, secret: doc.secret ?? undefined, cpuAlertThreshold: doc.cpuAlertThreshold, + cpuAlertCounter: doc.cpuAlertCounter, memoryAlertThreshold: doc.memoryAlertThreshold, + memoryAlertCounter: doc.memoryAlertCounter, diskAlertThreshold: doc.diskAlertThreshold, + diskAlertCounter: doc.diskAlertCounter, tempAlertThreshold: doc.tempAlertThreshold, + tempAlertCounter: doc.tempAlertCounter, selectedDisks: doc.selectedDisks ?? [], gameId: doc.gameId ?? undefined, group: doc.group ?? null, diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index d92b351a9..da95f4292 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -33,9 +33,13 @@ export interface Monitor { notifications: string[]; secret?: string; cpuAlertThreshold: number; + cpuAlertCounter: number; memoryAlertThreshold: number; + memoryAlertCounter: number; diskAlertThreshold: number; + diskAlertCounter: number; tempAlertThreshold: number; + tempAlertCounter: number; selectedDisks: string[]; gameId?: string; group: string | null; From 62778886e1184e63f5470174b296d802058267c4 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 21:55:47 +0000 Subject: [PATCH 44/58] use counters --- .../SuperSimpleQueue/SuperSimpleQueueHelper.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index ec8a792f2..621253f81 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -246,12 +246,12 @@ class SuperSimpleQueueHelper { const anyThresholdBreached = Object.values(breaches).some((b) => b); - // Check if countdown has reached zero for any threshold + // Check if countdown counter has reached zero for any breached threshold const shouldNotifyThreshold = - (breaches.cpu && monitor.cpuAlertThreshold <= 0) || - (breaches.memory && monitor.memoryAlertThreshold <= 0) || - (breaches.disk && monitor.diskAlertThreshold <= 0) || - (breaches.temp && monitor.tempAlertThreshold <= 0); + (breaches.cpu && monitor.cpuAlertCounter <= 0) || + (breaches.memory && monitor.memoryAlertCounter <= 0) || + (breaches.disk && monitor.diskAlertCounter <= 0) || + (breaches.temp && monitor.tempAlertCounter <= 0); // Decision logic for hardware if (statusChanged && monitor.status === "down") { From 22645d86f718ce3833edaf50f6d6a05b9ae8b2c6 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 22:14:51 +0000 Subject: [PATCH 45/58] handle infra thresholds --- .../SuperSimpleQueueHelper.ts | 45 +++------------ .../service/infrastructure/statusService.ts | 56 +++++++++++++++++++ server/src/types/network.ts | 6 ++ 3 files changed, 71 insertions(+), 36 deletions(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 621253f81..3a5de5970 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -183,7 +183,7 @@ class SuperSimpleQueueHelper { } private evaluateMonitorAction(statusChangeResult: StatusChangeResult, networkResponse: MonitorStatusResponse): MonitorActionDecision { - const { monitor, statusChanged, prevStatus } = statusChangeResult; + const { monitor, statusChanged, prevStatus, thresholdBreaches } = statusChangeResult; // Initialize result const decision: MonitorActionDecision = { @@ -213,45 +213,18 @@ class SuperSimpleQueueHelper { } // CASE 2: Hardware - const payload = networkResponse.payload as HardwareStatusPayload; - const metrics = payload?.data; - - if (!metrics) { - return decision; // No metrics, can't evaluate + if (!thresholdBreaches) { + return decision; // No breach data available } - // Evaluate threshold breaches - // CPU check - const cpuUsage = metrics.cpu?.usage_percent ?? -1; - const cpuBreach = cpuUsage !== -1 && cpuUsage > monitor.cpuAlertThreshold / 100; - - // Memory check - const memoryUsage = metrics.memory?.usage_percent ?? -1; - const memoryBreach = memoryUsage !== -1 && memoryUsage > monitor.memoryAlertThreshold / 100; - - // Disk check - const diskBreach = - metrics.disk?.some((d: any) => typeof d?.usage_percent === "number" && d.usage_percent > monitor.diskAlertThreshold / 100) ?? false; - - // Temperature check (alert if ANY sensor exceeds threshold) - const temps = metrics.cpu?.temperature ?? []; - const tempBreach = temps.some((temp: number) => temp > monitor.tempAlertThreshold); - - const breaches = { - cpu: cpuBreach, - memory: memoryBreach, - disk: diskBreach, - temp: tempBreach, - }; - - const anyThresholdBreached = Object.values(breaches).some((b) => b); + const anyThresholdBreached = Object.values(thresholdBreaches).some((b) => b); // Check if countdown counter has reached zero for any breached threshold const shouldNotifyThreshold = - (breaches.cpu && monitor.cpuAlertCounter <= 0) || - (breaches.memory && monitor.memoryAlertCounter <= 0) || - (breaches.disk && monitor.diskAlertCounter <= 0) || - (breaches.temp && monitor.tempAlertCounter <= 0); + (thresholdBreaches.cpu && monitor.cpuAlertCounter <= 0) || + (thresholdBreaches.memory && monitor.memoryAlertCounter <= 0) || + (thresholdBreaches.disk && monitor.diskAlertCounter <= 0) || + (thresholdBreaches.temp && monitor.tempAlertCounter <= 0); // Decision logic for hardware if (statusChanged && monitor.status === "down") { @@ -271,7 +244,7 @@ class SuperSimpleQueueHelper { decision.shouldSendNotification = true; decision.incidentReason = "threshold_breach"; decision.notificationReason = "threshold_breach"; - decision.thresholdBreaches = breaches; + decision.thresholdBreaches = thresholdBreaches; } return decision; diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index 0ab47f85b..cf9e1945a 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -253,6 +253,61 @@ export class StatusService implements IStatusService { } monitor.status = newStatus; + + // Evaluate hardware threshold breaches (only for hardware monitors) + let thresholdBreaches: { cpu: boolean; memory: boolean; disk: boolean; temp: boolean } | undefined; + if (monitor.type === "hardware" && statusResponse.payload) { + const payload = statusResponse.payload as HardwareStatusPayload; + const metrics = payload?.data; + + if (metrics) { + // Evaluate threshold breaches + const cpuUsage = metrics.cpu?.usage_percent ?? -1; + const cpuBreach = cpuUsage !== -1 && cpuUsage > monitor.cpuAlertThreshold / 100; + + const memoryUsage = metrics.memory?.usage_percent ?? -1; + const memoryBreach = memoryUsage !== -1 && memoryUsage > monitor.memoryAlertThreshold / 100; + + const diskBreach = + metrics.disk?.some((d: any) => typeof d?.usage_percent === "number" && d.usage_percent > monitor.diskAlertThreshold / 100) ?? false; + + const temps = metrics.cpu?.temperature ?? []; + const tempBreach = temps.some((temp: number) => temp > monitor.tempAlertThreshold); + + thresholdBreaches = { + cpu: cpuBreach, + memory: memoryBreach, + disk: diskBreach, + temp: tempBreach, + }; + + // Update counters: decrement if breached, reset to 5 if not breached + if (cpuBreach) { + monitor.cpuAlertCounter = Math.max(0, monitor.cpuAlertCounter - 1); + } else { + monitor.cpuAlertCounter = 5; + } + + if (memoryBreach) { + monitor.memoryAlertCounter = Math.max(0, monitor.memoryAlertCounter - 1); + } else { + monitor.memoryAlertCounter = 5; + } + + if (diskBreach) { + monitor.diskAlertCounter = Math.max(0, monitor.diskAlertCounter - 1); + } else { + monitor.diskAlertCounter = 5; + } + + if (tempBreach) { + monitor.tempAlertCounter = Math.max(0, monitor.tempAlertCounter - 1); + } else { + monitor.tempAlertCounter = 5; + } + } + } + const updated = await this.monitorsRepository.updateById(monitor.id, monitor.teamId, monitor); return { @@ -261,6 +316,7 @@ export class StatusService implements IStatusService { prevStatus, code, timestamp: new Date().getTime(), + thresholdBreaches, }; } catch (error: any) { error.service = SERVICE_NAME; diff --git a/server/src/types/network.ts b/server/src/types/network.ts index 7fbfb79fe..d87f1ea4f 100644 --- a/server/src/types/network.ts +++ b/server/src/types/network.ts @@ -110,4 +110,10 @@ export type StatusChangeResult = { prevStatus: MonitorStatus; code: number; timestamp: number; + thresholdBreaches?: { + cpu: boolean; + memory: boolean; + disk: boolean; + temp: boolean; + }; }; From e50240885d7e608c5dbb51ea39339d5fc1721baf Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 22:25:15 +0000 Subject: [PATCH 46/58] debug logging --- .../SuperSimpleQueue/SuperSimpleQueueHelper.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 3a5de5970..78e7d54d7 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -115,6 +115,10 @@ class SuperSimpleQueueHelper { // Step 4. Update monitor status const statusChangeResult = await this.statusService.updateMonitorStatus(status, check); + // Step 5. Get decisions + const decision = this.evaluateMonitorAction(statusChangeResult); + console.log(JSON.stringify(decision, null, 2)); + // Step 5 handle notifications (best effort, continue even in event of failure, don't wait) this.notificationsService .handleNotifications(statusChangeResult.monitor, status, statusChangeResult.prevStatus, statusChangeResult.statusChanged) @@ -182,7 +186,7 @@ class SuperSimpleQueueHelper { return maintenanceWindowIsActive; } - private evaluateMonitorAction(statusChangeResult: StatusChangeResult, networkResponse: MonitorStatusResponse): MonitorActionDecision { + private evaluateMonitorAction(statusChangeResult: StatusChangeResult): MonitorActionDecision { const { monitor, statusChanged, prevStatus, thresholdBreaches } = statusChangeResult; // Initialize result From b75c1a4fcbeb481c04b1c81d71845ebf3a7a9632 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 22:29:06 +0000 Subject: [PATCH 47/58] create incident on hardware breach --- .../SuperSimpleQueueHelper.ts | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 78e7d54d7..7e4c94586 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -218,10 +218,22 @@ class SuperSimpleQueueHelper { // CASE 2: Hardware if (!thresholdBreaches) { - return decision; // No breach data available + // No breach data available - still handle status changes + if (statusChanged && monitor.status === "down") { + decision.shouldCreateIncident = true; + decision.shouldSendNotification = true; + decision.incidentReason = "status_down"; + decision.notificationReason = "status_change"; + } else if (statusChanged && monitor.status === "up" && prevStatus === "down") { + decision.shouldResolveIncident = true; + decision.shouldSendNotification = true; + decision.notificationReason = "status_change"; + } + return decision; } const anyThresholdBreached = Object.values(thresholdBreaches).some((b) => b); + const noThresholdsBreached = Object.values(thresholdBreaches).every((b) => !b); // Check if countdown counter has reached zero for any breached threshold const shouldNotifyThreshold = @@ -233,6 +245,7 @@ class SuperSimpleQueueHelper { // Decision logic for hardware if (statusChanged && monitor.status === "down") { // Hardware service is DOWN (unreachable) + // Status down takes precedence over threshold breaches decision.shouldCreateIncident = true; decision.shouldSendNotification = true; decision.incidentReason = "status_down"; @@ -243,12 +256,17 @@ class SuperSimpleQueueHelper { decision.shouldSendNotification = true; decision.notificationReason = "status_change"; } else if (anyThresholdBreached && shouldNotifyThreshold) { - // Threshold breach alert (service is UP but metrics are high) + // Threshold breach: Counters have reached zero + // Create incident if service is UP but metrics exceed thresholds decision.shouldCreateIncident = true; decision.shouldSendNotification = true; decision.incidentReason = "threshold_breach"; decision.notificationReason = "threshold_breach"; decision.thresholdBreaches = thresholdBreaches; + } else if (noThresholdsBreached && !anyThresholdBreached) { + // All thresholds returned to normal - resolve any active threshold incidents + decision.shouldResolveIncident = true; + // Don't send notification for resolution (can be added later if needed) } return decision; From 68db4b8701f76588f6ff74d900ba760399d034c0 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 22:52:14 +0000 Subject: [PATCH 48/58] breached status --- .../v2/design-elements/StatusLabel.tsx | 2 + client/src/Types/Monitor.ts | 1 + client/src/Utils/MonitorUtils.ts | 3 + client/src/locales/en.json | 1 + .../SuperSimpleQueueHelper.ts | 69 +++---------------- .../service/infrastructure/statusService.ts | 31 ++++++++- server/src/types/monitor.ts | 2 +- 7 files changed, 48 insertions(+), 61 deletions(-) diff --git a/client/src/Components/v2/design-elements/StatusLabel.tsx b/client/src/Components/v2/design-elements/StatusLabel.tsx index cf404421e..19bb8d157 100644 --- a/client/src/Components/v2/design-elements/StatusLabel.tsx +++ b/client/src/Components/v2/design-elements/StatusLabel.tsx @@ -21,6 +21,8 @@ export const StatusLabel = ({ status, sx }: { status: MonitorStatus; sx?: SxProp return t("pages.common.monitors.status.up"); } else if (status === "down") { return t("pages.common.monitors.status.down"); + } else if (status === "breached") { + return t("pages.common.monitors.status.breached"); } else if (status === "maintenance") { return t("pages.common.monitors.status.maintenance"); } else if (status === "paused") { diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index 0c7cea5bd..cf637c184 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -18,6 +18,7 @@ export const MonitorStatuses = [ "paused", "initializing", "maintenance", + "breached", ] as const; export type MonitorStatus = (typeof MonitorStatuses)[number]; diff --git a/client/src/Utils/MonitorUtils.ts b/client/src/Utils/MonitorUtils.ts index 02c291efc..b73fc5bc4 100644 --- a/client/src/Utils/MonitorUtils.ts +++ b/client/src/Utils/MonitorUtils.ts @@ -23,6 +23,9 @@ export const getStatusPalette = (status: MonitorStatus): PaletteKey => { if (status === "down") { return "error"; } + if (status === "breached") { + return "error"; + } return "warning"; }; diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 8e18d8e2a..d8a46fb7c 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -387,6 +387,7 @@ }, "status": { "down": "down", + "breached": "breached", "initializing": "initializing", "maintenance": "maintenance", "paused": "paused", diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 7e4c94586..4082368a7 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -187,7 +187,7 @@ class SuperSimpleQueueHelper { } private evaluateMonitorAction(statusChangeResult: StatusChangeResult): MonitorActionDecision { - const { monitor, statusChanged, prevStatus, thresholdBreaches } = statusChangeResult; + const { monitor, statusChanged, prevStatus } = statusChangeResult; // Initialize result const decision: MonitorActionDecision = { @@ -198,75 +198,28 @@ class SuperSimpleQueueHelper { notificationReason: null, }; - // CASE 1: Non-hardware - if (monitor.type !== "hardware") { - if (statusChanged) { - // This is the current state of the monitor AFTER the most recent check - if (monitor.status === "down") { - decision.shouldCreateIncident = true; - decision.shouldSendNotification = true; - decision.incidentReason = "status_down"; - decision.notificationReason = "status_change"; - } else if (monitor.status === "up" && prevStatus === "down") { - decision.shouldResolveIncident = true; - decision.shouldSendNotification = true; - decision.notificationReason = "status_change"; - } - } + // Simplified logic: Just check status changes + if (!statusChanged) { return decision; } - // CASE 2: Hardware - if (!thresholdBreaches) { - // No breach data available - still handle status changes - if (statusChanged && monitor.status === "down") { - decision.shouldCreateIncident = true; - decision.shouldSendNotification = true; - decision.incidentReason = "status_down"; - decision.notificationReason = "status_change"; - } else if (statusChanged && monitor.status === "up" && prevStatus === "down") { - decision.shouldResolveIncident = true; - decision.shouldSendNotification = true; - decision.notificationReason = "status_change"; - } - return decision; - } - - const anyThresholdBreached = Object.values(thresholdBreaches).some((b) => b); - const noThresholdsBreached = Object.values(thresholdBreaches).every((b) => !b); - - // Check if countdown counter has reached zero for any breached threshold - const shouldNotifyThreshold = - (thresholdBreaches.cpu && monitor.cpuAlertCounter <= 0) || - (thresholdBreaches.memory && monitor.memoryAlertCounter <= 0) || - (thresholdBreaches.disk && monitor.diskAlertCounter <= 0) || - (thresholdBreaches.temp && monitor.tempAlertCounter <= 0); - - // Decision logic for hardware - if (statusChanged && monitor.status === "down") { - // Hardware service is DOWN (unreachable) - // Status down takes precedence over threshold breaches + if (monitor.status === "down") { + // Monitor went down (unreachable) decision.shouldCreateIncident = true; decision.shouldSendNotification = true; decision.incidentReason = "status_down"; decision.notificationReason = "status_change"; - } else if (statusChanged && monitor.status === "up" && prevStatus === "down") { - // Hardware service recovered - decision.shouldResolveIncident = true; - decision.shouldSendNotification = true; - decision.notificationReason = "status_change"; - } else if (anyThresholdBreached && shouldNotifyThreshold) { - // Threshold breach: Counters have reached zero - // Create incident if service is UP but metrics exceed thresholds + } else if (monitor.status === "breached") { + // Hardware monitor exceeded thresholds decision.shouldCreateIncident = true; decision.shouldSendNotification = true; decision.incidentReason = "threshold_breach"; decision.notificationReason = "threshold_breach"; - decision.thresholdBreaches = thresholdBreaches; - } else if (noThresholdsBreached && !anyThresholdBreached) { - // All thresholds returned to normal - resolve any active threshold incidents + } else if (monitor.status === "up" && (prevStatus === "down" || prevStatus === "breached")) { + // Monitor recovered from down or breached state decision.shouldResolveIncident = true; - // Don't send notification for resolution (can be added later if needed) + decision.shouldSendNotification = true; + decision.notificationReason = "status_change"; } return decision; diff --git a/server/src/service/infrastructure/statusService.ts b/server/src/service/infrastructure/statusService.ts index cf9e1945a..b01131bbe 100755 --- a/server/src/service/infrastructure/statusService.ts +++ b/server/src/service/infrastructure/statusService.ts @@ -252,8 +252,6 @@ export class StatusService implements IStatusService { statusChanged = true; } - monitor.status = newStatus; - // Evaluate hardware threshold breaches (only for hardware monitors) let thresholdBreaches: { cpu: boolean; memory: boolean; disk: boolean; temp: boolean } | undefined; if (monitor.type === "hardware" && statusResponse.payload) { @@ -305,9 +303,38 @@ export class StatusService implements IStatusService { } else { monitor.tempAlertCounter = 5; } + + // Check if any counter has reached zero (initial breach) + const anyCounterZero = + monitor.cpuAlertCounter === 0 || monitor.memoryAlertCounter === 0 || monitor.diskAlertCounter === 0 || monitor.tempAlertCounter === 0; + + const anyThresholdBreached = cpuBreach || memoryBreach || diskBreach || tempBreach; + const allThresholdsNormal = !cpuBreach && !memoryBreach && !diskBreach && !tempBreach; + + // Update monitor status based on threshold breach state + if (newStatus !== "down") { + // Don't override "down" status - service unreachable takes precedence + // Check current monitor status, not newStatus for comparison + if (anyCounterZero && anyThresholdBreached && monitor.status !== "breached") { + // Initial breach: counter hit zero, change status to breached + newStatus = "breached"; + statusChanged = true; + } else if (anyCounterZero && anyThresholdBreached && monitor.status === "breached") { + // Already breached, keep status but don't mark as changed + newStatus = "breached"; + // statusChanged remains false + } else if (allThresholdsNormal && monitor.status === "breached") { + // All thresholds returned to normal, recover from breached state + newStatus = "up"; + statusChanged = true; + } + } } } + // Apply the final status + monitor.status = newStatus; + const updated = await this.monitorsRepository.updateById(monitor.id, monitor.teamId, monitor); return { diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index da95f4292..021172c3f 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -4,7 +4,7 @@ export type { CheckSnapshot } from "@/types/check.js"; export const MonitorTypes = ["http", "ping", "pagespeed", "hardware", "docker", "port", "game", "unknown"] as const; export type MonitorType = (typeof MonitorTypes)[number]; -export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance"] as const; +export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance", "breached"] as const; export type MonitorStatus = (typeof MonitorStatuses)[number]; export type MonitorMatchMethod = "equal" | "include" | "regex" | ""; From 32a7bd6543b4b72f8b5b7038a601fbb1fa4f70d3 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 22:57:27 +0000 Subject: [PATCH 49/58] add breached status to summary header --- .../Components/v2/design-elements/StatusBox.tsx | 11 +++++++++++ .../v2/monitors/HeaderMonitorsSummary.tsx | 2 ++ client/src/Types/Monitor.ts | 1 + .../monitors/MongoMonitorsRepository.ts | 17 ++++++++++++++++- server/src/types/monitor.ts | 1 + 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/client/src/Components/v2/design-elements/StatusBox.tsx b/client/src/Components/v2/design-elements/StatusBox.tsx index 1be76988b..73a881736 100644 --- a/client/src/Components/v2/design-elements/StatusBox.tsx +++ b/client/src/Components/v2/design-elements/StatusBox.tsx @@ -139,6 +139,17 @@ export const InitializingStatusBox = ({ n }: { n: number }) => { /> ); }; +export const BreachedStatusBox = ({ n }: { n: number }) => { + const theme = useTheme(); + const { t } = useTranslation(); + return ( + + ); +}; export const TotalChecksBox = ({ n }: { n: number }) => { const theme = useTheme(); diff --git a/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx b/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx index b2a93a807..49a4fd471 100644 --- a/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx +++ b/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx @@ -3,6 +3,7 @@ import { DownStatusBox, PausedStatusBox, InitializingStatusBox, + BreachedStatusBox, } from "@/Components/v2/design-elements"; import Stack from "@mui/material/Stack"; @@ -22,6 +23,7 @@ export const HeaderMonitorsSummary = ({ summary }: MonitorsSummaryProps) => { > + diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index cf637c184..043076704 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -72,6 +72,7 @@ export interface MonitorsSummary { pausedMonitors: number; initializingMonitors: number; maintenanceMonitors: number; + breachedMonitors: number; } export interface MonitorsWithChecksResponse { diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index c942d749a..c6f3266a6 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -252,13 +252,28 @@ class MongoMonitorsRepository implements IMonitorsRepository { $cond: [{ $eq: ["$status", "maintenance"] }, 1, 0], }, }, + breachedMonitors: { + $sum: { + $cond: [{ $eq: ["$status", "breached"] }, 1, 0], + }, + }, }, }, { $project: { _id: 0 } }, ]; const [summary] = await MonitorModel.aggregate(pipeline); - return summary ?? { totalMonitors: 0, upMonitors: 0, downMonitors: 0, pausedMonitors: 0, initializingMonitors: 0, maintenanceMonitors: 0 }; + return ( + summary ?? { + totalMonitors: 0, + upMonitors: 0, + downMonitors: 0, + pausedMonitors: 0, + initializingMonitors: 0, + maintenanceMonitors: 0, + breachedMonitors: 0, + } + ); }; findGroupsByTeamId = async (teamId: string): Promise => { diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index 021172c3f..a196aaae6 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -55,6 +55,7 @@ export interface MonitorsSummary { pausedMonitors: number; initializingMonitors: number; maintenanceMonitors: number; + breachedMonitors: number; } export interface MonitorsWithChecksByTeamIdResult { From 70ae15725eeaa1b75040953a046892190bee6c82 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Feb 2026 23:09:27 +0000 Subject: [PATCH 50/58] conditinally render breached stauts box --- .../src/Components/v2/monitors/HeaderMonitorsSummary.tsx | 8 ++++++-- client/src/Pages/Infrastructure/Monitors/index.tsx | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx b/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx index 49a4fd471..38a6adfde 100644 --- a/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx +++ b/client/src/Components/v2/monitors/HeaderMonitorsSummary.tsx @@ -12,9 +12,13 @@ import { useTheme } from "@mui/material"; interface MonitorsSummaryProps { summary: MonitorsSummary | null; + showBreached?: boolean; } -export const HeaderMonitorsSummary = ({ summary }: MonitorsSummaryProps) => { +export const HeaderMonitorsSummary = ({ + summary, + showBreached = false, +}: MonitorsSummaryProps) => { const theme = useTheme(); return ( { > - + {showBreached && } diff --git a/client/src/Pages/Infrastructure/Monitors/index.tsx b/client/src/Pages/Infrastructure/Monitors/index.tsx index 01de1c09c..8d1ef1a3a 100644 --- a/client/src/Pages/Infrastructure/Monitors/index.tsx +++ b/client/src/Pages/Infrastructure/Monitors/index.tsx @@ -133,7 +133,10 @@ const InfrastructureMonitors = () => { isLoading={isLoading} isAdmin={isAdmin} /> - + Date: Sun, 15 Feb 2026 18:09:21 +0000 Subject: [PATCH 51/58] use decision object in incidentService --- .../src/service/business/incidentService.ts | 28 +++++++---- .../SuperSimpleQueueHelper.ts | 47 +++++++++---------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/server/src/service/business/incidentService.ts b/server/src/service/business/incidentService.ts index 881f98f56..bcb17d3a5 100644 --- a/server/src/service/business/incidentService.ts +++ b/server/src/service/business/incidentService.ts @@ -4,6 +4,7 @@ import { AppError } from "@/utils/AppError.js"; import { ParseBoolean } from "@/utils/utils.js"; import type { IIncidentsRepository, IMonitorsRepository, IUsersRepository } from "@/repositories/index.js"; import type { Incident } from "@/types/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; const dateRangeLookup: Record = { recent: new Date(new Date().setHours(new Date().getHours() - 2)), @@ -43,10 +44,14 @@ class IncidentService { return IncidentService.SERVICE_NAME; } - handleIncident = async (monitor: Monitor, code: number): Promise => { + handleIncident = async (monitor: Monitor, code: number, decision: MonitorActionDecision): Promise => { + if (!decision.shouldCreateIncident && !decision.shouldResolveIncident) { + return null; + } + const activeIncident = await this.incidentsRepository.findActiveByMonitorId(monitor.id, monitor.teamId); - // Monitor is down, create an incident - if (monitor.status === "down") { + + if (decision.shouldCreateIncident) { if (activeIncident) { return activeIncident; } else { @@ -61,14 +66,17 @@ class IncidentService { } } - // Monitor is up, resolve active incidents - if (!activeIncident) { - return null; + if (decision.shouldResolveIncident) { + if (!activeIncident) { + return null; + } + activeIncident.status = false; + activeIncident.endTime = Date.now().toString(); + activeIncident.resolutionType = "automatic"; + return await this.incidentsRepository.updateById(activeIncident.id, activeIncident.teamId, activeIncident); } - activeIncident.status = false; - activeIncident.endTime = Date.now().toString(); - activeIncident.resolutionType = "automatic"; - return await this.incidentsRepository.updateById(activeIncident.id, activeIncident.teamId, activeIncident); + + return null; }; resolveIncident = async (incidentId: string, userId: string, teamId: string, comment?: string, userEmail?: string) => { diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 4082368a7..84a26d1e2 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -117,33 +117,32 @@ class SuperSimpleQueueHelper { // Step 5. Get decisions const decision = this.evaluateMonitorAction(statusChangeResult); - console.log(JSON.stringify(decision, null, 2)); - // Step 5 handle notifications (best effort, continue even in event of failure, don't wait) - this.notificationsService - .handleNotifications(statusChangeResult.monitor, status, statusChangeResult.prevStatus, statusChangeResult.statusChanged) - .catch((error: any) => { - this.logger.error({ - message: error.message, - service: SERVICE_NAME, - method: "getMonitorJob", - details: `Error sending notifications for job ${statusChangeResult.monitor.id}: ${error.message}`, - stack: error.stack, + // Step 6. Handle notifications (best effort, continue even in event of failure, don't wait) + if (decision.shouldSendNotification) { + this.notificationsService + .handleNotifications(statusChangeResult.monitor, status, statusChangeResult.prevStatus, statusChangeResult.statusChanged) + .catch((error: any) => { + this.logger.error({ + message: error.message, + service: SERVICE_NAME, + method: "getMonitorJob", + details: `Error sending notifications for job ${statusChangeResult.monitor.id}: ${error.message}`, + stack: error.stack, + }); }); - }); - - // Step 6. Handle incidents (best effort, don't wait) - if (statusChangeResult.statusChanged) { - this.incidentService.handleIncident(statusChangeResult.monitor, statusChangeResult.code).catch((error: any) => { - this.logger.warn({ - message: error.message, - service: SERVICE_NAME, - method: "getMonitorJob", - details: `Error handling incident for job ${monitor.id}: ${error.message}`, - stack: error.stack, - }); - }); } + + // Step 7. Handle incidents (best effort, don't wait) + this.incidentService.handleIncident(statusChangeResult.monitor, statusChangeResult.code, decision).catch((error: any) => { + this.logger.warn({ + message: error.message, + service: SERVICE_NAME, + method: "getMonitorJob", + details: `Error handling incident for job ${monitor.id}: ${error.message}`, + stack: error.stack, + }); + }); } catch (error: any) { this.logger.warn({ message: error.message, From 8020bfde21d5611050d6e0ebfb38affa0149b666 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 15 Feb 2026 18:20:42 +0000 Subject: [PATCH 52/58] refactor handleIncidents --- .../SuperSimpleQueueHelper.ts | 18 ++-- .../notificationProviders/utils.ts | 87 +++++++------------ .../infrastructure/notificationsService.ts | 42 ++------- 3 files changed, 46 insertions(+), 101 deletions(-) diff --git a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts index 84a26d1e2..274318ad7 100644 --- a/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts +++ b/server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts @@ -120,17 +120,15 @@ class SuperSimpleQueueHelper { // Step 6. Handle notifications (best effort, continue even in event of failure, don't wait) if (decision.shouldSendNotification) { - this.notificationsService - .handleNotifications(statusChangeResult.monitor, status, statusChangeResult.prevStatus, statusChangeResult.statusChanged) - .catch((error: any) => { - this.logger.error({ - message: error.message, - service: SERVICE_NAME, - method: "getMonitorJob", - details: `Error sending notifications for job ${statusChangeResult.monitor.id}: ${error.message}`, - stack: error.stack, - }); + this.notificationsService.handleNotifications(statusChangeResult.monitor, status, decision).catch((error: any) => { + this.logger.error({ + message: error.message, + service: SERVICE_NAME, + method: "getMonitorJob", + details: `Error sending notifications for job ${statusChangeResult.monitor.id}: ${error.message}`, + stack: error.stack, }); + }); } // Step 7. Handle incidents (best effort, don't wait) diff --git a/server/src/service/infrastructure/notificationProviders/utils.ts b/server/src/service/infrastructure/notificationProviders/utils.ts index ed9d0177c..b258ccd52 100644 --- a/server/src/service/infrastructure/notificationProviders/utils.ts +++ b/server/src/service/infrastructure/notificationProviders/utils.ts @@ -27,15 +27,22 @@ export const buildHardwareAlerts = ( const cpuThreshold = monitor.cpuAlertThreshold !== undefined ? monitor.cpuAlertThreshold / 100 : -1; const memoryThreshold = monitor.memoryAlertThreshold !== undefined ? monitor.memoryAlertThreshold / 100 : -1; const diskThreshold = monitor.diskAlertThreshold !== undefined ? monitor.diskAlertThreshold / 100 : -1; + const tempThreshold = monitor.tempAlertThreshold !== undefined ? monitor.tempAlertThreshold : -1; const payload = networkResponse?.payload as HardwareStatusPayload; const metrics = payload.data || {}; - const { cpu: { usage_percent: cpuUsage = -1 } = {}, memory: { usage_percent: memoryUsage = -1 } = {}, disk = [] } = metrics; + const { cpu = {}, memory = {}, disk = [] } = metrics; + const cpuUsage = cpu.usage_percent ?? -1; + const memoryUsage = memory.usage_percent ?? -1; + // Get max temperature from CPU temperature sensors array + const temps = cpu.temperature ?? []; + const maxTemp = temps.length > 0 ? Math.max(...temps) : -1; const alerts: Record = { cpu: cpuThreshold !== -1 && cpuUsage > cpuThreshold ? true : false, memory: memoryThreshold !== -1 && memoryUsage > memoryThreshold ? true : false, disk: disk?.some((d) => diskThreshold !== -1 && typeof d?.usage_percent === "number" && d?.usage_percent > diskThreshold) ?? false, + temp: tempThreshold !== -1 && maxTemp > tempThreshold ? true : false, }; const alertsToSend = []; @@ -45,6 +52,7 @@ export const buildHardwareAlerts = ( { name: "URL", value: monitor.url, inline: false }, ]; const goToIncidentField = { name: `Go to incident`, value: `${clientHost}/infrastructure/${monitor.id}` }; + const formatDiscordAlert = { cpu: () => ({ title: "CPU alert", @@ -77,38 +85,33 @@ export const buildHardwareAlerts = ( goToIncidentField, ], }), + + temp: () => ({ + title: "Temperature alert", + description: `Your current temperature (${maxTemp.toFixed(0)}°C) is above your threshold (${tempThreshold.toFixed(0)}°C)`, + color: 15548997, + fields: [...monitorInfoFields, goToIncidentField], + footer: { text: "Checkmate" }, + }), }; - const alertTypes = ["cpu", "memory", "disk"] as const; - const alertThresholdKeyMap: Record<(typeof alertTypes)[number], "cpuAlertThreshold" | "memoryAlertThreshold" | "diskAlertThreshold"> = { - cpu: "cpuAlertThreshold", - memory: "memoryAlertThreshold", - disk: "diskAlertThreshold", - }; + + const alertTypes = ["cpu", "memory", "disk", "temp"] as const; + for (const type of alertTypes) { - const thresholdKey = alertThresholdKeyMap[type]; - // Iterate over each alert type to see if any need to be decremented if (alerts[type] === true) { - const nextValue = monitor[thresholdKey] - 1; - monitor[thresholdKey] = nextValue; // Decrement threshold if an alert is triggered - - if (monitor[thresholdKey] <= 0) { - // If threshold drops below 0, reset and send notification - monitor[thresholdKey] = 100; - - const formatAlert = { - cpu: () => `Your current CPU usage (${(cpuUsage * 100).toFixed(0)}%) is above your threshold (${(cpuThreshold * 100).toFixed(0)}%)`, - memory: () => - `Your current memory usage (${(memoryUsage * 100).toFixed(0)}%) is above your threshold (${(memoryThreshold * 100).toFixed(0)}%)`, - disk: () => - `Your current disk usage: ${disk - .map((d, idx) => `(Disk${idx}: ${(d?.usage_percent ?? 0 * 100).toFixed(0)}%)`) - .join(", ")} is above your threshold (${(diskThreshold * 100).toFixed(0)}%)`, - }; - alertsToSend.push(formatAlert[type]()); - discordEmbeds.push(formatDiscordAlert[type]()); - } + const formatAlert = { + cpu: () => `Your current CPU usage (${(cpuUsage * 100).toFixed(0)}%) is above your threshold (${(cpuThreshold * 100).toFixed(0)}%)`, + memory: () => + `Your current memory usage (${(memoryUsage * 100).toFixed(0)}%) is above your threshold (${(memoryThreshold * 100).toFixed(0)}%)`, + disk: () => + `Your current disk usage: ${disk.map((d, idx) => `(Disk${idx}: ${(d?.usage_percent ?? 0 * 100).toFixed(0)}%)`).join(", ")} is above your threshold (${(diskThreshold * 100).toFixed(0)}%)`, + temp: () => `Your current temperature (${maxTemp.toFixed(0)}°C) is above your threshold (${tempThreshold.toFixed(0)}°C)`, + }; + alertsToSend.push(formatAlert[type]()); + discordEmbeds.push(formatDiscordAlert[type]()); } } + const discordPayload = discordEmbeds.length ? { embeds: discordEmbeds } : null; return { alertsToSend, discordPayload }; }; @@ -125,34 +128,6 @@ export const buildHardwareWebhookBody = (alerts: string[], monitor: Monitor): st return content; }; -export const shouldSendHardwareAlert = (monitor: Monitor, networkResponse: MonitorStatusResponse): boolean => { - // Thresholds are stored as percentages (0-100), convert to decimal (0-1) for comparison - const cpuThreshold = monitor.cpuAlertThreshold !== undefined ? monitor.cpuAlertThreshold / 100 : -1; - const memoryThreshold = monitor.memoryAlertThreshold !== undefined ? monitor.memoryAlertThreshold / 100 : -1; - const diskThreshold = monitor.diskAlertThreshold !== undefined ? monitor.diskAlertThreshold / 100 : -1; - - const payload = networkResponse?.payload as HardwareStatusPayload; - const metrics = payload.data || {}; - const { cpu: { usage_percent: cpuUsage = -1 } = {}, memory: { usage_percent: memoryUsage = -1 } = {}, disk = [] } = metrics; - - const cpuBreach = cpuThreshold !== -1 && cpuUsage > cpuThreshold; - if (cpuBreach && monitor.cpuAlertThreshold - 1 <= 0) { - return true; - } - - const memoryBreach = memoryThreshold !== -1 && memoryUsage > memoryThreshold; - if (memoryBreach && monitor.memoryAlertThreshold - 1 <= 0) { - return true; - } - - const diskBreach = disk?.some((d) => diskThreshold !== -1 && typeof d?.usage_percent === "number" && d?.usage_percent > diskThreshold); - if (diskBreach && monitor.diskAlertThreshold - 1 <= 0) { - return true; - } - - return false; -}; - export const buildWebhookBody = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { const { status, code } = monitorStatusResponse; const { localTimeZone, localTime, utcTime } = getTime(); diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index b2ae59b7c..6174dceb3 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -1,7 +1,7 @@ import type { HardwareStatusPayload, Monitor, MonitorStatusResponse, Notification, MonitorStatus } from "@/types/index.js"; -import { shouldSendHardwareAlert } from "@/service/infrastructure/notificationProviders/utils.js"; import { IMonitorsRepository, INotificationsRepository } from "@/repositories/index.js"; import { INotificationProvider } from "./notificationProviders/INotificationProvider.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; export interface INotificationsService { createNotification: (notificationData: Partial) => Promise; @@ -9,12 +9,7 @@ export interface INotificationsService { findNotificationsByTeamId: (teamId: string) => Promise; updateById(id: string, teamId: string, updateData: Partial): Promise; deleteById: (id: string, teamId: string) => Promise; - handleNotifications: ( - monitor: Monitor, - monitorStatusResponse: MonitorStatusResponse, - prevStatus: MonitorStatus, - statusChanged: boolean - ) => Promise; + handleNotifications: (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => Promise; sendTestNotification: (notification: Notification) => Promise; testAllNotifications: (notificationIds: string[]) => Promise; @@ -229,36 +224,13 @@ export class NotificationsService implements INotificationsService { return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus); }; - handleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, prevStatus: MonitorStatus, statusChanged: boolean) => { - const { type } = monitor; - const payload = monitorStatusResponse.payload as HardwareStatusPayload; - // If this is a non-hardeware type monitor and status did not change, we're done - if (type !== "hardware" && statusChanged === false) return false; - // if prevStatus is undefined, monitor is resuming, we're done - if (type !== "hardware" && prevStatus === undefined) return false; - - // Deal with hardware thresholds - if (type === "hardware") { - // Check if any thresholds are set - const hasThresholds = - monitor.cpuAlertThreshold !== undefined || - monitor.memoryAlertThreshold !== undefined || - monitor.diskAlertThreshold !== undefined || - monitor.tempAlertThreshold !== undefined; - - if (!hasThresholds) return false; // No thresholds set, we're done - const metrics = payload?.data ?? null; - if (metrics === null) return false; // No metrics, we're done - - // We should send a notificaiton - - const shouldSend = shouldSendHardwareAlert(monitor, monitorStatusResponse); - if (shouldSend === false) return false; - - return await this.sendNotifications(monitor, monitorStatusResponse); + handleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + // Early return if no notification should be sent + if (!decision.shouldSendNotification) { + return false; } - // We should send a notification for non-hardware monitor status change + // Send notifications based on decision return await this.sendNotifications(monitor, monitorStatusResponse); }; From be8580ee996cba398b5c5a428d1681dadb88b2b9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 15 Feb 2026 18:35:54 +0000 Subject: [PATCH 53/58] update providers --- .../INotificationProvider.ts | 8 ++++- .../notificationProviders/discord.ts | 12 +++++-- .../notificationProviders/email.ts | 30 +++++++++++++--- .../notificationProviders/matrix.ts | 19 +++++++--- .../notificationProviders/pagerduty.ts | 24 ++++++++++--- .../notificationProviders/slack.ts | 24 ++++++++++--- .../notificationProviders/utils.ts | 4 +-- .../notificationProviders/webhook.ts | 19 +++++++--- .../infrastructure/notificationsService.ts | 35 ++++++++++++++----- 9 files changed, 140 insertions(+), 35 deletions(-) diff --git a/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts b/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts index 2d363d6b3..0a1dbf876 100644 --- a/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts +++ b/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts @@ -1,6 +1,12 @@ import type { Monitor, Notification, Alert, MonitorStatusResponse } from "@/types/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; export interface INotificationProvider { - sendAlert: (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => Promise; + sendAlert: ( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ) => Promise; sendTestAlert(notification: Notification): Promise; } diff --git a/server/src/service/infrastructure/notificationProviders/discord.ts b/server/src/service/infrastructure/notificationProviders/discord.ts index ad1f2f28a..200b8af2c 100644 --- a/server/src/service/infrastructure/notificationProviders/discord.ts +++ b/server/src/service/infrastructure/notificationProviders/discord.ts @@ -1,6 +1,7 @@ const SERVICE_NAME = "DiscordProvider"; import type { Monitor, Notification, MonitorStatusResponse } from "@/types/index.js"; import { INotificationProvider } from "@/service/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import { buildHardwareAlerts, buildDiscordBody, getTestMessage } from "@/service/infrastructure/notificationProviders/utils.js"; import got from "got"; @@ -10,15 +11,20 @@ export class DiscordProvider implements INotificationProvider { constructor(logger: any) { this.logger = logger; } - private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + // For status changes (recovery), use standard format + if (decision.notificationReason === "status_change") { + return buildDiscordBody(monitor, monitorStatusResponse); + } + // For threshold breaches, use hardware alert format const { discordPayload } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); return discordPayload; }; - sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent(monitor, monitorStatusResponse); + body = this.getHardwareContent(monitor, monitorStatusResponse, decision); } else { body = buildDiscordBody(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/email.ts b/server/src/service/infrastructure/notificationProviders/email.ts index 32ccf1859..802c44b80 100644 --- a/server/src/service/infrastructure/notificationProviders/email.ts +++ b/server/src/service/infrastructure/notificationProviders/email.ts @@ -1,6 +1,7 @@ const SERVICE_NAME = "EmailProvider"; import type { Monitor, Notification, MonitorStatusResponse } from "@/types/index.js"; import { INotificationProvider } from "@/service/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import { buildHardwareAlerts, buildHardwareEmail, buildEmail, buildTestEmail } from "@/service/infrastructure/notificationProviders/utils.js"; export class EmailProvider implements INotificationProvider { @@ -12,21 +13,42 @@ export class EmailProvider implements INotificationProvider { this.logger = logger; } - private buildHardwareEmail = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + private buildHardwareEmail = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + // For status changes (recovery), use standard email format + if (decision.notificationReason === "status_change") { + return await buildEmail(this.emailService, monitor); + } + // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); const html = buildHardwareEmail(this.emailService, monitor, alertsToSend); return html; }; - async sendAlert(notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): Promise { + async sendAlert( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ): Promise { // For grouped notifications (identified by ":" in name), customize subject to indicate multiple services. // Example: "2 services: Service A, Service B" becomes "Alert: 2 services are down" const isGroupedNotification = monitor.name.includes(":"); - const subject = isGroupedNotification ? `Alert: ${monitor.name} are down` : `Monitor ${monitor.name} is down`; + + // Build subject based on notification reason and monitor status + let subject: string; + if (isGroupedNotification) { + subject = `Alert: ${monitor.name} are down`; + } else if (decision.notificationReason === "threshold_breach") { + subject = `Monitor ${monitor.name} threshold breached`; + } else if (monitor.status === "up") { + subject = `Monitor ${monitor.name} is back up`; + } else { + subject = `Monitor ${monitor.name} is down`; + } let html; if (monitor.type === "hardware") { - html = this.buildHardwareEmail(monitor, monitorStatusResponse); + html = await this.buildHardwareEmail(monitor, monitorStatusResponse, decision); } else { html = await buildEmail(this.emailService, monitor); } diff --git a/server/src/service/infrastructure/notificationProviders/matrix.ts b/server/src/service/infrastructure/notificationProviders/matrix.ts index 8914dbf80..5a65a7909 100644 --- a/server/src/service/infrastructure/notificationProviders/matrix.ts +++ b/server/src/service/infrastructure/notificationProviders/matrix.ts @@ -1,6 +1,7 @@ const SERVICE_NAME = "MatrixProvider"; import got from "got"; import type { INotificationProvider } from "@/service/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import type { Notification, Monitor, MonitorStatusResponse } from "@/types/index.js"; import { buildHardwareAlerts, @@ -15,9 +16,19 @@ export class MatrixProvider implements INotificationProvider { constructor(logger: any) { this.logger = logger; } - private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + private getHardwareContent = ( + clientHost: string, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ) => { + // For status changes (recovery), use standard format + if (decision.notificationReason === "status_change") { + return buildWebhookBody(monitor, monitorStatusResponse); + } + // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(alertsToSend, monitor); + const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); return body; }; @@ -26,12 +37,12 @@ export class MatrixProvider implements INotificationProvider { return body; }; - sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { const { homeserverUrl, accessToken, roomId } = notification; let content; if (monitor.type === "hardware") { - content = this.getHardwareContent(monitor, monitorStatusResponse); + content = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); } else { content = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/pagerduty.ts b/server/src/service/infrastructure/notificationProviders/pagerduty.ts index f65e50c68..8ed4ccc68 100644 --- a/server/src/service/infrastructure/notificationProviders/pagerduty.ts +++ b/server/src/service/infrastructure/notificationProviders/pagerduty.ts @@ -1,6 +1,7 @@ const SERVICE_NAME = "PagerDutyProvider"; import got from "got"; import type { Monitor, Notification, MonitorStatusResponse } from "@/types/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import { INotificationProvider } from "@/service/index.js"; import { buildHardwareAlerts, @@ -15,9 +16,19 @@ export class PagerDutyProvider implements INotificationProvider { constructor(logger: any) { this.logger = logger; } - private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + private getHardwareContent = ( + clientHost: string, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ) => { + // For status changes (recovery), use standard format + if (decision.notificationReason === "status_change") { + return buildWebhookBody(monitor, monitorStatusResponse); + } + // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(alertsToSend, monitor); + const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); return body; }; @@ -26,10 +37,15 @@ export class PagerDutyProvider implements INotificationProvider { return body; }; - async sendAlert(notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): Promise { + async sendAlert( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ): Promise { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent(monitor, monitorStatusResponse); + body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); } else { body = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/slack.ts b/server/src/service/infrastructure/notificationProviders/slack.ts index 2aeb442eb..0e7710b3f 100644 --- a/server/src/service/infrastructure/notificationProviders/slack.ts +++ b/server/src/service/infrastructure/notificationProviders/slack.ts @@ -1,6 +1,7 @@ const SERVICE_NAME = "SlackProvider"; import type { Monitor, Notification, MonitorStatusResponse } from "@/types/index.js"; import { INotificationProvider } from "@/service/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import { buildHardwareAlerts, buildHardwareWebhookBody, @@ -15,9 +16,19 @@ export class SlackProvider implements INotificationProvider { constructor(logger: any) { this.logger = logger; } - private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + private getHardwareContent = ( + clientHost: string, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ) => { + // For status changes (recovery), use standard format + if (decision.notificationReason === "status_change") { + return buildWebhookBody(monitor, monitorStatusResponse); + } + // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(alertsToSend, monitor); + const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); return body; }; @@ -26,10 +37,15 @@ export class SlackProvider implements INotificationProvider { return body; }; - async sendAlert(notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): Promise { + async sendAlert( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ): Promise { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent(monitor, monitorStatusResponse); + body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); } else { body = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/utils.ts b/server/src/service/infrastructure/notificationProviders/utils.ts index b258ccd52..bb1c928ca 100644 --- a/server/src/service/infrastructure/notificationProviders/utils.ts +++ b/server/src/service/infrastructure/notificationProviders/utils.ts @@ -123,8 +123,8 @@ export const buildHardwareNotificationMessage = (clientHost: string, alerts: any return alertText.map((alert) => alert).join("\n"); }; -export const buildHardwareWebhookBody = (alerts: string[], monitor: Monitor): string => { - const content = alerts.map((alert) => alert).join("\n"); +export const buildHardwareWebhookBody = (clientHost: string, alerts: string[], monitor: Monitor): string => { + const content = buildHardwareNotificationMessage(clientHost, alerts, monitor); return content; }; diff --git a/server/src/service/infrastructure/notificationProviders/webhook.ts b/server/src/service/infrastructure/notificationProviders/webhook.ts index 9e743ae53..dfc5f4763 100644 --- a/server/src/service/infrastructure/notificationProviders/webhook.ts +++ b/server/src/service/infrastructure/notificationProviders/webhook.ts @@ -1,6 +1,7 @@ const SERVICE_NAME = "WebhookProvider"; import type { Monitor, Alert, Notification, MonitorStatusResponse } from "@/types/index.js"; import { INotificationProvider } from "@/service/index.js"; +import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import { buildHardwareAlerts, buildHardwareWebhookBody, @@ -15,9 +16,19 @@ export class WebhookProvider implements INotificationProvider { constructor(logger: any) { this.logger = logger; } - private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + private getHardwareContent = ( + clientHost: string, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ) => { + // For status changes (recovery), use standard format + if (decision.notificationReason === "status_change") { + return buildWebhookBody(monitor, monitorStatusResponse); + } + // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(alertsToSend, monitor); + const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); return body; }; @@ -26,10 +37,10 @@ export class WebhookProvider implements INotificationProvider { return body; }; - sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent(monitor, monitorStatusResponse); + body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); } else { body = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index 6174dceb3..f43402f30 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -41,6 +41,7 @@ export class NotificationsService implements INotificationsService { createdAt: number; } >; + private currentDecision?: MonitorActionDecision; constructor( notificationsRepository: INotificationsRepository, @@ -83,17 +84,17 @@ export class NotificationsService implements INotificationsService { private send = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): Promise => { switch (notification.type) { case "email": - return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse); + return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); case "slack": - return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse); + return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); case "discord": - return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse); + return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); case "pager_duty": - return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse); + return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); case "matrix": - return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse); + return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); case "webhook": - return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse); + return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); default: return false; } @@ -157,7 +158,15 @@ export class NotificationsService implements INotificationsService { this.pendingEmailGroups.delete(key); try { - await this.flushEmailGroup(notification, group.monitors, group.statusResponses); + // For grouped notifications (always DOWN), create a decision + const groupedDecision: MonitorActionDecision = { + shouldCreateIncident: false, + shouldResolveIncident: false, + shouldSendNotification: true, + incidentReason: "status_down", + notificationReason: "status_change", + }; + await this.flushEmailGroup(notification, group.monitors, group.statusResponses, groupedDecision); } catch (error: any) { this.logger.error({ message: error?.message, @@ -196,7 +205,12 @@ export class NotificationsService implements INotificationsService { * @param statusResponses Array of status responses (parallel to monitors) * @returns true if email was sent successfully, false otherwise */ - private flushEmailGroup = async (notification: Notification, monitors: Monitor[], statusResponses: MonitorStatusResponse[]): Promise => { + private flushEmailGroup = async ( + notification: Notification, + monitors: Monitor[], + statusResponses: MonitorStatusResponse[], + decision: MonitorActionDecision + ): Promise => { if (!monitors.length || !statusResponses.length) { return false; } @@ -221,7 +235,7 @@ export class NotificationsService implements INotificationsService { }; // Reuse existing email provider to send grouped notification. - return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus); + return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus, decision); }; handleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { @@ -230,6 +244,9 @@ export class NotificationsService implements INotificationsService { return false; } + // Store decision for use in send method + this.currentDecision = decision; + // Send notifications based on decision return await this.sendNotifications(monitor, monitorStatusResponse); }; From 412a3b7cc9d0801687cdc98c411a6e4f1bdad9e7 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Feb 2026 00:17:51 +0000 Subject: [PATCH 54/58] remove redundant method --- .../infrastructure/notificationProviders/matrix.ts | 4 ++-- .../infrastructure/notificationProviders/pagerduty.ts | 4 ++-- .../infrastructure/notificationProviders/slack.ts | 4 ++-- .../infrastructure/notificationProviders/utils.ts | 9 ++------- .../infrastructure/notificationProviders/webhook.ts | 4 ++-- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/server/src/service/infrastructure/notificationProviders/matrix.ts b/server/src/service/infrastructure/notificationProviders/matrix.ts index 5a65a7909..afca6da95 100644 --- a/server/src/service/infrastructure/notificationProviders/matrix.ts +++ b/server/src/service/infrastructure/notificationProviders/matrix.ts @@ -5,7 +5,7 @@ import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimple import type { Notification, Monitor, MonitorStatusResponse } from "@/types/index.js"; import { buildHardwareAlerts, - buildHardwareWebhookBody, + buildHardwareNotificationMessage, buildWebhookBody, getTestMessage, } from "@/service/infrastructure/notificationProviders/utils.js"; @@ -28,7 +28,7 @@ export class MatrixProvider implements INotificationProvider { } // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); + const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; diff --git a/server/src/service/infrastructure/notificationProviders/pagerduty.ts b/server/src/service/infrastructure/notificationProviders/pagerduty.ts index 8ed4ccc68..0634f46b4 100644 --- a/server/src/service/infrastructure/notificationProviders/pagerduty.ts +++ b/server/src/service/infrastructure/notificationProviders/pagerduty.ts @@ -5,7 +5,7 @@ import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimple import { INotificationProvider } from "@/service/index.js"; import { buildHardwareAlerts, - buildHardwareWebhookBody, + buildHardwareNotificationMessage, buildWebhookBody, getTestMessage, } from "@/service/infrastructure/notificationProviders/utils.js"; @@ -28,7 +28,7 @@ export class PagerDutyProvider implements INotificationProvider { } // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); + const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; diff --git a/server/src/service/infrastructure/notificationProviders/slack.ts b/server/src/service/infrastructure/notificationProviders/slack.ts index 0e7710b3f..da7338a75 100644 --- a/server/src/service/infrastructure/notificationProviders/slack.ts +++ b/server/src/service/infrastructure/notificationProviders/slack.ts @@ -4,7 +4,7 @@ import { INotificationProvider } from "@/service/index.js"; import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import { buildHardwareAlerts, - buildHardwareWebhookBody, + buildHardwareNotificationMessage, buildWebhookBody, getTestMessage, } from "@/service/infrastructure/notificationProviders/utils.js"; @@ -28,7 +28,7 @@ export class SlackProvider implements INotificationProvider { } // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); + const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; diff --git a/server/src/service/infrastructure/notificationProviders/utils.ts b/server/src/service/infrastructure/notificationProviders/utils.ts index bb1c928ca..72797c1d0 100644 --- a/server/src/service/infrastructure/notificationProviders/utils.ts +++ b/server/src/service/infrastructure/notificationProviders/utils.ts @@ -116,16 +116,11 @@ export const buildHardwareAlerts = ( return { alertsToSend, discordPayload }; }; -export const buildHardwareNotificationMessage = (clientHost: string, alerts: any, monitor: Monitor) => { +export const buildHardwareNotificationMessage = (clientHost: string, alerts: string[], monitor: Monitor): string => { const alertsHeader = [`Monitor: ${monitor.name}`, `URL: ${monitor.url}`]; const alertFooter = [`Go to incident: ${clientHost}/infrastructure/${monitor.id}`]; const alertText = alerts.length > 0 ? [...alertsHeader, ...alerts, ...alertFooter] : []; - return alertText.map((alert) => alert).join("\n"); -}; - -export const buildHardwareWebhookBody = (clientHost: string, alerts: string[], monitor: Monitor): string => { - const content = buildHardwareNotificationMessage(clientHost, alerts, monitor); - return content; + return alertText.join("\n"); }; export const buildWebhookBody = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { diff --git a/server/src/service/infrastructure/notificationProviders/webhook.ts b/server/src/service/infrastructure/notificationProviders/webhook.ts index dfc5f4763..13a0ae8ef 100644 --- a/server/src/service/infrastructure/notificationProviders/webhook.ts +++ b/server/src/service/infrastructure/notificationProviders/webhook.ts @@ -4,7 +4,7 @@ import { INotificationProvider } from "@/service/index.js"; import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import { buildHardwareAlerts, - buildHardwareWebhookBody, + buildHardwareNotificationMessage, buildWebhookBody, getTestMessage, } from "@/service/infrastructure/notificationProviders/utils.js"; @@ -28,7 +28,7 @@ export class WebhookProvider implements INotificationProvider { } // For threshold breaches, use hardware alert format const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); - const body = buildHardwareWebhookBody(clientHost, alertsToSend, monitor); + const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; From a8ecd44abf44cf80ea1fd6e4787046da6109400b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Feb 2026 00:39:34 +0000 Subject: [PATCH 55/58] inject settings service, extract client host --- server/src/config/services.ts | 1 + .../INotificationProvider.ts | 3 ++- .../notificationProviders/discord.ts | 19 +++++++++++--- .../notificationProviders/email.ts | 14 +++++++--- .../notificationProviders/matrix.ts | 12 ++++++--- .../notificationProviders/pagerduty.ts | 7 ++--- .../notificationProviders/slack.ts | 7 ++--- .../notificationProviders/webhook.ts | 12 ++++++--- .../infrastructure/notificationsService.ts | 26 ++++++++++++++----- 9 files changed, 73 insertions(+), 28 deletions(-) diff --git a/server/src/config/services.ts b/server/src/config/services.ts index f88bc2584..67c16ff6a 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -182,6 +182,7 @@ export const initializeServices = async ({ discordProvider, pagerDutyProvider, matrixProvider, + settingsService, logger ); diff --git a/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts b/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts index 0a1dbf876..21a221c9c 100644 --- a/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts +++ b/server/src/service/infrastructure/notificationProviders/INotificationProvider.ts @@ -6,7 +6,8 @@ export interface INotificationProvider { notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, - decision: MonitorActionDecision + decision: MonitorActionDecision, + clientHost: string ) => Promise; sendTestAlert(notification: Notification): Promise; } diff --git a/server/src/service/infrastructure/notificationProviders/discord.ts b/server/src/service/infrastructure/notificationProviders/discord.ts index 200b8af2c..560c18aae 100644 --- a/server/src/service/infrastructure/notificationProviders/discord.ts +++ b/server/src/service/infrastructure/notificationProviders/discord.ts @@ -11,20 +11,31 @@ export class DiscordProvider implements INotificationProvider { constructor(logger: any) { this.logger = logger; } - private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + private getHardwareContent = ( + clientHost: string, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ) => { // For status changes (recovery), use standard format if (decision.notificationReason === "status_change") { return buildDiscordBody(monitor, monitorStatusResponse); } // For threshold breaches, use hardware alert format - const { discordPayload } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); + const { discordPayload } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse); return discordPayload; }; - sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + sendAlert = async ( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision, + clientHost: string + ) => { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent(monitor, monitorStatusResponse, decision); + body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision); } else { body = buildDiscordBody(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/email.ts b/server/src/service/infrastructure/notificationProviders/email.ts index 802c44b80..fd15034d1 100644 --- a/server/src/service/infrastructure/notificationProviders/email.ts +++ b/server/src/service/infrastructure/notificationProviders/email.ts @@ -13,13 +13,18 @@ export class EmailProvider implements INotificationProvider { this.logger = logger; } - private buildHardwareEmail = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + private buildHardwareEmail = async ( + clientHost: string, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ) => { // For status changes (recovery), use standard email format if (decision.notificationReason === "status_change") { return await buildEmail(this.emailService, monitor); } // For threshold breaches, use hardware alert format - const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); + const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse); const html = buildHardwareEmail(this.emailService, monitor, alertsToSend); return html; }; @@ -28,7 +33,8 @@ export class EmailProvider implements INotificationProvider { notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, - decision: MonitorActionDecision + decision: MonitorActionDecision, + clientHost: string ): Promise { // For grouped notifications (identified by ":" in name), customize subject to indicate multiple services. // Example: "2 services: Service A, Service B" becomes "Alert: 2 services are down" @@ -48,7 +54,7 @@ export class EmailProvider implements INotificationProvider { let html; if (monitor.type === "hardware") { - html = await this.buildHardwareEmail(monitor, monitorStatusResponse, decision); + html = await this.buildHardwareEmail(clientHost, monitor, monitorStatusResponse, decision); } else { html = await buildEmail(this.emailService, monitor); } diff --git a/server/src/service/infrastructure/notificationProviders/matrix.ts b/server/src/service/infrastructure/notificationProviders/matrix.ts index afca6da95..f2543886d 100644 --- a/server/src/service/infrastructure/notificationProviders/matrix.ts +++ b/server/src/service/infrastructure/notificationProviders/matrix.ts @@ -27,7 +27,7 @@ export class MatrixProvider implements INotificationProvider { return buildWebhookBody(monitor, monitorStatusResponse); } // For threshold breaches, use hardware alert format - const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); + const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse); const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; @@ -37,12 +37,18 @@ export class MatrixProvider implements INotificationProvider { return body; }; - sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + sendAlert = async ( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision, + clientHost: string + ) => { const { homeserverUrl, accessToken, roomId } = notification; let content; if (monitor.type === "hardware") { - content = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); + content = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision); } else { content = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/pagerduty.ts b/server/src/service/infrastructure/notificationProviders/pagerduty.ts index 0634f46b4..291cd7de5 100644 --- a/server/src/service/infrastructure/notificationProviders/pagerduty.ts +++ b/server/src/service/infrastructure/notificationProviders/pagerduty.ts @@ -27,7 +27,7 @@ export class PagerDutyProvider implements INotificationProvider { return buildWebhookBody(monitor, monitorStatusResponse); } // For threshold breaches, use hardware alert format - const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); + const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse); const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; @@ -41,11 +41,12 @@ export class PagerDutyProvider implements INotificationProvider { notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, - decision: MonitorActionDecision + decision: MonitorActionDecision, + clientHost: string ): Promise { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); + body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision); } else { body = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/slack.ts b/server/src/service/infrastructure/notificationProviders/slack.ts index da7338a75..f99af48d4 100644 --- a/server/src/service/infrastructure/notificationProviders/slack.ts +++ b/server/src/service/infrastructure/notificationProviders/slack.ts @@ -27,7 +27,7 @@ export class SlackProvider implements INotificationProvider { return buildWebhookBody(monitor, monitorStatusResponse); } // For threshold breaches, use hardware alert format - const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); + const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse); const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; @@ -41,11 +41,12 @@ export class SlackProvider implements INotificationProvider { notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, - decision: MonitorActionDecision + decision: MonitorActionDecision, + clientHost: string ): Promise { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); + body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision); } else { body = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationProviders/webhook.ts b/server/src/service/infrastructure/notificationProviders/webhook.ts index 13a0ae8ef..17d871950 100644 --- a/server/src/service/infrastructure/notificationProviders/webhook.ts +++ b/server/src/service/infrastructure/notificationProviders/webhook.ts @@ -27,7 +27,7 @@ export class WebhookProvider implements INotificationProvider { return buildWebhookBody(monitor, monitorStatusResponse); } // For threshold breaches, use hardware alert format - const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse); + const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse); const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor); return body; }; @@ -37,10 +37,16 @@ export class WebhookProvider implements INotificationProvider { return body; }; - sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { + sendAlert = async ( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision, + clientHost: string + ) => { let body; if (monitor.type === "hardware") { - body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision); + body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision); } else { body = this.getContent(monitor, monitorStatusResponse); } diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index f43402f30..e3dc36747 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -2,6 +2,7 @@ import type { HardwareStatusPayload, Monitor, MonitorStatusResponse, Notificatio import { IMonitorsRepository, INotificationsRepository } from "@/repositories/index.js"; import { INotificationProvider } from "./notificationProviders/INotificationProvider.js"; import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; +import type { ISettingsService } from "@/service/system/settingsService.js"; export interface INotificationsService { createNotification: (notificationData: Partial) => Promise; @@ -29,6 +30,7 @@ export class NotificationsService implements INotificationsService { private pagerDutyProvider: INotificationProvider; private matrixProvider: INotificationProvider; private logger: any; + private settingsService: ISettingsService; // Email grouping (batching) configuration private emailGroupingWindowMs: number; @@ -52,6 +54,7 @@ export class NotificationsService implements INotificationsService { discordProvider: INotificationProvider, pagerDutyProvider: INotificationProvider, matrixProvider: INotificationProvider, + settingsService: ISettingsService, logger: any ) { this.notificationsRepository = notificationsRepository; @@ -62,6 +65,7 @@ export class NotificationsService implements INotificationsService { this.discordProvider = discordProvider; this.pagerDutyProvider = pagerDutyProvider; this.matrixProvider = matrixProvider; + this.settingsService = settingsService; this.logger = logger; // Configure email grouping window (in milliseconds). @@ -82,19 +86,21 @@ export class NotificationsService implements INotificationsService { } private send = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): Promise => { + const settings = this.settingsService.getSettings(); + const clientHost = settings.clientHost || "Host not defined"; switch (notification.type) { case "email": - return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); + return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); case "slack": - return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); + return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); case "discord": - return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); + return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); case "pager_duty": - return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); + return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); case "matrix": - return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); + return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); case "webhook": - return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!); + return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); default: return false; } @@ -215,6 +221,12 @@ export class NotificationsService implements INotificationsService { return false; } + const { clientHost } = this.settingsService.getSettings(); + if (!clientHost) { + this.logger.warn({ message: "CLIENT_HOST not configured", service: SERVICE_NAME, method: "flushEmailGroup" }); + return false; + } + // Build a combined monitor name listing all affected services. // Example: "Service A, Service B" (2 services) or "Service A" (1 service) const uniqueNames = Array.from(new Set(monitors.map((m) => m.name))); @@ -235,7 +247,7 @@ export class NotificationsService implements INotificationsService { }; // Reuse existing email provider to send grouped notification. - return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus, decision); + return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus, decision, clientHost); }; handleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { From 55885ea0079139cba17d867ecdb14cc741bba641 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Feb 2026 18:25:35 +0000 Subject: [PATCH 56/58] remove global decision --- .../infrastructure/notificationsService.ts | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index e3dc36747..93a436df9 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -39,11 +39,11 @@ export class NotificationsService implements INotificationsService { { monitors: Monitor[]; statusResponses: MonitorStatusResponse[]; + decisions: MonitorActionDecision[]; timer: ReturnType; createdAt: number; } >; - private currentDecision?: MonitorActionDecision; constructor( notificationsRepository: INotificationsRepository, @@ -85,39 +85,45 @@ export class NotificationsService implements INotificationsService { this.pendingEmailGroups = new Map(); } - private send = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): Promise => { + private send = async ( + notification: Notification, + monitor: Monitor, + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision + ): Promise => { const settings = this.settingsService.getSettings(); const clientHost = settings.clientHost || "Host not defined"; + switch (notification.type) { case "email": - return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); + return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse, decision, clientHost); case "slack": - return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); + return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse, decision, clientHost); case "discord": - return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); + return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse, decision, clientHost); case "pager_duty": - return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); + return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse, decision, clientHost); case "matrix": - return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); + return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse, decision, clientHost); case "webhook": - return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost); + return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse, decision, clientHost); default: return false; } }; - private sendNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse) => { + private sendNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { const notificationIds = monitor.notifications ?? []; const notifications = await this.notificationsRepository.findNotificationsByIds(notificationIds); const tasks = notifications.map((notification) => { // Only group emails, only for DOWN transitions, and only if a window is configured. if (notification.type === "email" && this.emailGroupingWindowMs > 0 && monitorStatusResponse.status === false) { - return this.queueGroupedEmailNotification(notification, monitor, monitorStatusResponse); + return this.queueGroupedEmailNotification(notification, monitor, monitorStatusResponse, decision); } // For all other cases (UP notifications or non-email channels), send immediately. - return this.send(notification, monitor, monitorStatusResponse); + return this.send(notification, monitor, monitorStatusResponse, decision); }); const outcomes = await Promise.all(tasks); @@ -144,11 +150,12 @@ export class NotificationsService implements INotificationsService { private queueGroupedEmailNotification = async ( notification: Notification, monitor: Monitor, - monitorStatusResponse: MonitorStatusResponse + monitorStatusResponse: MonitorStatusResponse, + decision: MonitorActionDecision ): Promise => { // If grouping is disabled, fallback to immediate send. if (this.emailGroupingWindowMs <= 0) { - return await this.send(notification, monitor, monitorStatusResponse); + return await this.send(notification, monitor, monitorStatusResponse, decision); } const key = notification.id; @@ -164,15 +171,9 @@ export class NotificationsService implements INotificationsService { this.pendingEmailGroups.delete(key); try { - // For grouped notifications (always DOWN), create a decision - const groupedDecision: MonitorActionDecision = { - shouldCreateIncident: false, - shouldResolveIncident: false, - shouldSendNotification: true, - incidentReason: "status_down", - notificationReason: "status_change", - }; - await this.flushEmailGroup(notification, group.monitors, group.statusResponses, groupedDecision); + // Use the first decision from the group (they should all be similar for grouped notifications) + const firstDecision = group.decisions[0]!; + await this.flushEmailGroup(notification, group.monitors, group.statusResponses, firstDecision); } catch (error: any) { this.logger.error({ message: error?.message, @@ -186,6 +187,7 @@ export class NotificationsService implements INotificationsService { this.pendingEmailGroups.set(key, { monitors: [monitor], statusResponses: [monitorStatusResponse], + decisions: [decision], timer, createdAt: now, }); @@ -193,6 +195,7 @@ export class NotificationsService implements INotificationsService { // Append to existing group. existingGroup.monitors.push(monitor); existingGroup.statusResponses.push(monitorStatusResponse); + existingGroup.decisions.push(decision); } // Consider queueing as "succeeded" from the caller's perspective. @@ -256,11 +259,8 @@ export class NotificationsService implements INotificationsService { return false; } - // Store decision for use in send method - this.currentDecision = decision; - // Send notifications based on decision - return await this.sendNotifications(monitor, monitorStatusResponse); + return await this.sendNotifications(monitor, monitorStatusResponse, decision); }; sendTestNotification = async (notification: Notification) => { From e7a7c0e60383eebdbf88f9954cb4a67271adec65 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Feb 2026 18:39:41 +0000 Subject: [PATCH 57/58] remove grouping --- .../infrastructure/notificationsService.ts | 156 +----------------- 1 file changed, 3 insertions(+), 153 deletions(-) diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index 93a436df9..7fe825da0 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -32,19 +32,6 @@ export class NotificationsService implements INotificationsService { private logger: any; private settingsService: ISettingsService; - // Email grouping (batching) configuration - private emailGroupingWindowMs: number; - private pendingEmailGroups: Map< - string, - { - monitors: Monitor[]; - statusResponses: MonitorStatusResponse[]; - decisions: MonitorActionDecision[]; - timer: ReturnType; - createdAt: number; - } - >; - constructor( notificationsRepository: INotificationsRepository, monitorsRepository: IMonitorsRepository, @@ -67,22 +54,6 @@ export class NotificationsService implements INotificationsService { this.matrixProvider = matrixProvider; this.settingsService = settingsService; this.logger = logger; - - // Configure email grouping window (in milliseconds). - // When > 0, multiple DOWN events for monitors that share the same - // email notification within this window will be batched into a single email. - const rawGroupingWindow = process.env.NOTIFICATION_GROUP_WINDOW_MS ?? process.env.NOTIFICATION_GROUP_WINDOW_SECONDS; - let groupingWindowMs = 0; - if (rawGroupingWindow) { - const parsed = Number(rawGroupingWindow); - if (!Number.isNaN(parsed) && parsed > 0) { - // If value looks like seconds (small number), convert to ms. - // This allows either milliseconds (e.g. 60000) or seconds (e.g. 60). - groupingWindowMs = parsed <= 300 ? parsed * 1000 : parsed; - } - } - this.emailGroupingWindowMs = groupingWindowMs; - this.pendingEmailGroups = new Map(); } private send = async ( @@ -116,15 +87,7 @@ export class NotificationsService implements INotificationsService { const notificationIds = monitor.notifications ?? []; const notifications = await this.notificationsRepository.findNotificationsByIds(notificationIds); - const tasks = notifications.map((notification) => { - // Only group emails, only for DOWN transitions, and only if a window is configured. - if (notification.type === "email" && this.emailGroupingWindowMs > 0 && monitorStatusResponse.status === false) { - return this.queueGroupedEmailNotification(notification, monitor, monitorStatusResponse, decision); - } - - // For all other cases (UP notifications or non-email channels), send immediately. - return this.send(notification, monitor, monitorStatusResponse, decision); - }); + const tasks = notifications.map((notification) => this.send(notification, monitor, monitorStatusResponse, decision)); const outcomes = await Promise.all(tasks); const succeeded = outcomes.filter(Boolean).length; @@ -133,126 +96,13 @@ export class NotificationsService implements INotificationsService { this.logger.warn({ message: `Notification send completed with ${succeeded} success, ${failed} failure(s)`, service: SERVICE_NAME, - method: "getMonitorJob", + method: "sendNotifications", }); } - // Return true if all notificaitons succeeded + // Return true if all notifications succeeded return succeeded === notifications.length; }; - /** - * Queue a DOWN email notification to be potentially grouped with other - * DOWN events for the same email notification within the configured window. - * - * This method returns immediately; the actual email is sent asynchronously - * when the grouping window expires. - */ - private queueGroupedEmailNotification = async ( - notification: Notification, - monitor: Monitor, - monitorStatusResponse: MonitorStatusResponse, - decision: MonitorActionDecision - ): Promise => { - // If grouping is disabled, fallback to immediate send. - if (this.emailGroupingWindowMs <= 0) { - return await this.send(notification, monitor, monitorStatusResponse, decision); - } - - const key = notification.id; - const now = Date.now(); - const existingGroup = this.pendingEmailGroups.get(key); - - if (!existingGroup) { - // Create a new group and schedule a flush after the window expires. - const timer = setTimeout(async () => { - const group = this.pendingEmailGroups.get(key); - if (!group) return; - - this.pendingEmailGroups.delete(key); - - try { - // Use the first decision from the group (they should all be similar for grouped notifications) - const firstDecision = group.decisions[0]!; - await this.flushEmailGroup(notification, group.monitors, group.statusResponses, firstDecision); - } catch (error: any) { - this.logger.error({ - message: error?.message, - service: SERVICE_NAME, - method: "flushEmailGroup", - stack: error?.stack, - }); - } - }, this.emailGroupingWindowMs); - - this.pendingEmailGroups.set(key, { - monitors: [monitor], - statusResponses: [monitorStatusResponse], - decisions: [decision], - timer, - createdAt: now, - }); - } else { - // Append to existing group. - existingGroup.monitors.push(monitor); - existingGroup.statusResponses.push(monitorStatusResponse); - existingGroup.decisions.push(decision); - } - - // Consider queueing as "succeeded" from the caller's perspective. - return true; - }; - - /** - * Flush a grouped set of DOWN events into a single email. - * - * To avoid changing email templates, we construct a synthetic Monitor - * whose name concisely lists all affected services. The existing - * `serverIsDownTemplate` is then reused. - * - * @param notification The email notification to send to - * @param monitors Array of monitors that went down - * @param statusResponses Array of status responses (parallel to monitors) - * @returns true if email was sent successfully, false otherwise - */ - private flushEmailGroup = async ( - notification: Notification, - monitors: Monitor[], - statusResponses: MonitorStatusResponse[], - decision: MonitorActionDecision - ): Promise => { - if (!monitors.length || !statusResponses.length) { - return false; - } - - const { clientHost } = this.settingsService.getSettings(); - if (!clientHost) { - this.logger.warn({ message: "CLIENT_HOST not configured", service: SERVICE_NAME, method: "flushEmailGroup" }); - return false; - } - - // Build a combined monitor name listing all affected services. - // Example: "Service A, Service B" (2 services) or "Service A" (1 service) - const uniqueNames = Array.from(new Set(monitors.map((m) => m.name))); - const servicesCount = uniqueNames.length; - const servicesList = uniqueNames.join(", "); - - const combinedName = servicesCount === 1 ? servicesList : `${servicesCount} services: ${servicesList}`; - - // Use the first monitor as a base for URL and other fields. - const baseMonitor = monitors[0]!; - const baseStatus = statusResponses[0]!; - - // Create a shallow clone so we don't mutate the original entity. - // This preserves monitor properties while overriding the name for grouped display. - const syntheticMonitor: Monitor = { - ...baseMonitor, - name: combinedName, - }; - - // Reuse existing email provider to send grouped notification. - return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus, decision, clientHost); - }; - handleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => { // Early return if no notification should be sent if (!decision.shouldSendNotification) { From 27f3def9bdd6cf9457c6851c72226a3a6b8defb3 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Feb 2026 18:43:03 +0000 Subject: [PATCH 58/58] correct logger type --- server/src/service/infrastructure/notificationsService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/service/infrastructure/notificationsService.ts b/server/src/service/infrastructure/notificationsService.ts index 7fe825da0..5f057f0c5 100644 --- a/server/src/service/infrastructure/notificationsService.ts +++ b/server/src/service/infrastructure/notificationsService.ts @@ -3,6 +3,7 @@ import { IMonitorsRepository, INotificationsRepository } from "@/repositories/in import { INotificationProvider } from "./notificationProviders/INotificationProvider.js"; import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js"; import type { ISettingsService } from "@/service/system/settingsService.js"; +import { ILogger } from "@/utils/logger.js"; export interface INotificationsService { createNotification: (notificationData: Partial) => Promise; @@ -29,7 +30,7 @@ export class NotificationsService implements INotificationsService { private discordProvider: INotificationProvider; private pagerDutyProvider: INotificationProvider; private matrixProvider: INotificationProvider; - private logger: any; + private logger: ILogger; private settingsService: ISettingsService; constructor(