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/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; 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/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); 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); - } } 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; 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,