diff --git a/client/src/Components/v2/design-elements/BasePage.tsx b/client/src/Components/v2/design-elements/BasePage.tsx
index c8618fa67..de20fc005 100644
--- a/client/src/Components/v2/design-elements/BasePage.tsx
+++ b/client/src/Components/v2/design-elements/BasePage.tsx
@@ -1,15 +1,51 @@
import Stack from "@mui/material/Stack";
+import Alert from "@mui/material/Alert";
+import Link from "@mui/material/Link";
import {
ErrorFallback,
EmptyFallback,
EmptyMonitorFallback,
+ BaseFallback,
} from "@/Components/v2/design-elements/Fallback";
import { Breadcrumb } from "@/Components/v2/design-elements/Breadcrumb";
import CircularProgress from "@mui/material/CircularProgress";
import type { StackProps } from "@mui/material/Stack";
import { useTheme } from "@mui/material/styles";
-import { useTranslation } from "react-i18next";
+import { Trans, useTranslation } from "react-i18next";
+import { Link as RouterLink } from "react-router-dom";
+import { Typography } from "@mui/material";
+
+export const PageSpeedKeyPriorityFallback = () => {
+ return (
+
+
+
+
+ ),
+ }}
+ />
+
+
+
+ );
+};
+
interface BasePageProps extends StackProps {
loading?: boolean;
error?: boolean;
@@ -114,6 +150,7 @@ interface MonitorBasePageWithStatesProps extends StackProps {
page: string;
actionLink?: string;
children: React.ReactNode;
+ priorityFallback?: React.ReactNode;
}
const isEmpty = (items: any[]) => {
@@ -129,12 +166,25 @@ export const MonitorBasePageWithStates = ({
page,
actionLink,
children,
+ priorityFallback,
...props
}: MonitorBasePageWithStatesProps) => {
const { t } = useTranslation();
const showLoading = loading && (!items || items.length === 0);
+ if (priorityFallback) {
+ return (
+
+ {priorityFallback}
+
+ );
+ }
+
if (!loading && isEmpty(items)) {
return (
{
+ const { t } = useTranslation();
+ return (
+
+ );
+};
diff --git a/client/src/Components/v2/inputs/index.tsx b/client/src/Components/v2/inputs/index.tsx
index 87698a4f0..70e740dbd 100644
--- a/client/src/Components/v2/inputs/index.tsx
+++ b/client/src/Components/v2/inputs/index.tsx
@@ -8,3 +8,4 @@ export {
ToggleButtonInput as ToggleButton,
ToggleButtonGroupInput as ToggleButtonGroup,
} from "./ToggleButton";
+export { DialogInput as Dialog } from "./Dialog";
diff --git a/client/src/Components/v2/monitors/charts/HistogramPageSpeed.tsx b/client/src/Components/v2/monitors/charts/HistogramPageSpeed.tsx
new file mode 100644
index 000000000..d8d3b9829
--- /dev/null
+++ b/client/src/Components/v2/monitors/charts/HistogramPageSpeed.tsx
@@ -0,0 +1,107 @@
+import Stack from "@mui/material/Stack";
+import { Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip } from "recharts";
+import { HistogramPageSpeedTooltip } from "@/Components/v2/monitors/charts/HistogramPageSpeedTooltip";
+
+import { useTheme } from "@mui/material/styles";
+import type { Check } from "@/Types/Check";
+import type { MonitorStatus } from "@/Types/Monitor";
+
+import { getStatusColor } from "@/Utils/MonitorUtils";
+
+const processData = (checks: Check[]) => {
+ if (checks.length === 0) return [];
+ const formattedData: { score: number; date: string }[] = [];
+
+ const calculateScore = (entry: Check) => {
+ const accessibility = entry?.accessibility || 0;
+ const bestPractices = entry?.bestPractices || 0;
+ const performance = entry?.performance || 0;
+ const seo = entry?.seo || 0;
+ return Math.floor(((accessibility + bestPractices + performance + seo) / 4) * 100);
+ };
+
+ checks.forEach((entry) => {
+ const score = calculateScore(entry);
+ const date = entry.createdAt;
+ formattedData.push({ score, date });
+ });
+
+ return formattedData;
+};
+
+export const HistogramPageSpeed = ({
+ checks,
+ status,
+}: {
+ checks: Check[];
+ status: MonitorStatus;
+}) => {
+ const theme = useTheme();
+ const scores = processData(checks ?? []);
+ const color = getStatusColor(status, theme);
+ return (
+ event.stopPropagation()}
+ overflow={"hidden"}
+ sx={{
+ cursor: "default",
+ position: "relative",
+ }}
+ >
+
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/client/src/Components/v2/monitors/charts/HistogramPageSpeedTooltip.tsx b/client/src/Components/v2/monitors/charts/HistogramPageSpeedTooltip.tsx
new file mode 100644
index 000000000..6fd18251c
--- /dev/null
+++ b/client/src/Components/v2/monitors/charts/HistogramPageSpeedTooltip.tsx
@@ -0,0 +1,40 @@
+import Stack from "@mui/material/Stack";
+import Typography from "@mui/material/Typography";
+import { formatDateWithTz } from "@/Utils/TimeUtils";
+import type { TooltipProps } from "recharts";
+import { useTheme } from "@mui/material/styles";
+import { useSelector } from "react-redux";
+import type { RootState } from "@/Types/state";
+
+export const HistogramPageSpeedTooltip = ({
+ payload,
+}: TooltipProps) => {
+ const uiTimezone = useSelector((state: RootState) => state.ui.timezone);
+ const theme = useTheme();
+ return (
+
+
+ {formatDateWithTz(
+ payload?.[0]?.payload?.date ?? 0,
+ "MMMM D, YYYY, HH:mm A",
+ uiTimezone
+ )}
+
+
+ Score: {payload?.[0]?.payload?.score}
+
+
+ );
+};
diff --git a/client/src/Components/v2/monitors/index.tsx b/client/src/Components/v2/monitors/index.tsx
index de38d2cab..ca0aaa15e 100644
--- a/client/src/Components/v2/monitors/index.tsx
+++ b/client/src/Components/v2/monitors/index.tsx
@@ -3,3 +3,5 @@ export * from "./MonitorStatBoxes";
export * from "./charts/HistogramStatus";
export * from "./charts/RadialAvgResponse";
export * from "./charts/HistogramDetails";
+export * from "./charts/HistogramPageSpeed";
+export * from "./charts/HistogramPageSpeedTooltip";
diff --git a/client/src/Hooks/UseApi.ts b/client/src/Hooks/UseApi.ts
index 441c2b77b..aa71f01af 100644
--- a/client/src/Hooks/UseApi.ts
+++ b/client/src/Hooks/UseApi.ts
@@ -1,7 +1,7 @@
import useSWR from "swr";
import type { SWRConfiguration } from "swr";
import type { AxiosRequestConfig } from "axios";
-import { get, patch, post } from "@/Utils/ApiClient";
+import { get, patch, post, deleteOp } from "@/Utils/ApiClient";
import { useState } from "react";
import { useToast } from "@/Hooks/UseToast";
@@ -107,3 +107,38 @@ export const usePatch = () => {
return { patch: patchFn, loading, error };
};
+
+export const useDelete = () => {
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const { toastError, toastSuccess } = useToast();
+
+ const deleteFn = async (
+ endpoint: string,
+ config?: AxiosRequestConfig
+ ): Promise | null> => {
+ setLoading(true);
+ setError(null);
+
+ try {
+ const res = await deleteOp>(endpoint, {
+ ...config,
+ headers: {
+ ...config?.headers,
+ },
+ });
+ toastSuccess(res.data?.msg || "Operation successful");
+ return res.data;
+ } catch (err: any) {
+ console.error(err);
+ const errMsg = err?.response?.data?.message || err.message || "An error occurred";
+ toastError(errMsg);
+ setError(errMsg);
+ return null;
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return { deleteFn, loading, error };
+};
diff --git a/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx b/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx
new file mode 100644
index 000000000..f38e1c706
--- /dev/null
+++ b/client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx
@@ -0,0 +1,254 @@
+import Stack from "@mui/material/Stack";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import { Table, Pagination, StatusLabel } from "@/Components/v2/design-elements";
+import { HistogramPageSpeed } from "@/Components/v2/monitors";
+import { ArrowDown, ArrowUp } from "lucide-react";
+import type { Header } from "@/Components/v2/design-elements/Table";
+import { ActionsMenu } from "@/Components/v2/actions-menu";
+
+import { useTranslation } from "react-i18next";
+import useMediaQuery from "@mui/material/useMediaQuery";
+import { useTheme } from "@mui/material/styles";
+import { useNavigate } from "react-router-dom";
+import { usePatch } from "@/Hooks/UseApi";
+
+import type { Monitor, MonitorWithChecks } from "@/Types/Monitor";
+import type { ActionMenuItem } from "@/Components/v2/actions-menu";
+
+export const PageSpeedMonitorsTable = ({
+ monitors,
+ refetch,
+ setSelectedMonitor,
+ sortField,
+ setSortField,
+ sortOrder,
+ setSortOrder,
+ count,
+ page,
+ setPage,
+ rowsPerPage,
+ setRowsPerPage,
+}: {
+ monitors: MonitorWithChecks[];
+ refetch: Function;
+ setSelectedMonitor: Function;
+ sortField: string;
+ setSortField: (field: string) => void;
+ sortOrder: "asc" | "desc";
+ setSortOrder: (order: "asc" | "desc") => void;
+ count: number;
+ page: number;
+ setPage: (page: number) => void;
+ rowsPerPage: number;
+ setRowsPerPage: (rowsPerPage: number) => void;
+}) => {
+ const { t } = useTranslation();
+ const theme = useTheme();
+ const isSmall = useMediaQuery(theme.breakpoints.down("md"));
+ const navigate = useNavigate();
+ const {
+ patch,
+ // loading: isPatching,
+ // error: postError,
+ } = usePatch();
+
+ const handlePageChange = (
+ _e: React.MouseEvent | null,
+ newPage: number
+ ) => {
+ setPage(newPage);
+ };
+
+ const handleRowsPerPageChange = (
+ e: React.ChangeEvent
+ ) => {
+ const value = Number(e.target.value);
+ setPage(0);
+ setRowsPerPage(value);
+ };
+
+ const handleSort = (e: any, field: string) => {
+ e.preventDefault();
+ e.stopPropagation();
+ if (sortField === field) {
+ const newOrder = sortOrder === "asc" ? "desc" : "asc";
+ setSortOrder(newOrder);
+ } else {
+ setSortField(field);
+ setSortOrder("asc");
+ }
+ refetch();
+ };
+
+ const getActions = (monitor: Monitor): ActionMenuItem[] => {
+ return [
+ {
+ id: 1,
+ label: t("pages.common.monitors.actions.openSite"),
+ action: () => {
+ window.open(monitor.url, "_blank", "noreferrer");
+ },
+ closeMenu: true,
+ },
+ {
+ id: 2,
+ label: t("pages.common.monitors.actions.details"),
+ action: () => {
+ navigate(`${monitor.id}`);
+ },
+ },
+ {
+ id: 3,
+ label: t("pages.common.monitors.actions.incidents"),
+ action: () => {
+ navigate(`/incidents?monitorId=${monitor.id}`);
+ },
+ },
+ {
+ id: 4,
+ label: t("pages.common.monitors.actions.configure"),
+ action: () => {
+ navigate(`/pagespeed/configure/${monitor.id}`);
+ },
+ },
+ // {
+ // id: 5,
+ // label: "Clone",
+ // action: () => {
+
+ // },
+ // },
+ {
+ id: 6,
+ label:
+ monitor.isActive === false
+ ? t("common.buttons.resume")
+ : t("common.buttons.pause"),
+ action: async () => {
+ await patch(`/monitors/${monitor.id}/active`);
+ refetch();
+ },
+ closeMenu: true,
+ },
+ {
+ id: 7,
+ label: (
+
+ {t("common.buttons.delete")}
+
+ ),
+ action: () => {
+ setSelectedMonitor(monitor);
+ },
+ closeMenu: true,
+ },
+ ];
+ };
+
+ const getHeaders = () => {
+ const renderSortIcon = (isActive: boolean) => (
+
+ {isActive ? (
+ sortOrder === "asc" ? (
+
+ ) : (
+
+ )
+ ) : null}
+
+ );
+
+ const headers: Header[] = [
+ {
+ id: "name",
+ content: (
+ handleSort(e, "name")}
+ sx={{ cursor: "pointer" }}
+ >
+ {t("common.table.headers.name")}
+ {renderSortIcon(sortField === "name")}
+
+ ),
+ render: (row) => {
+ return row.name;
+ },
+ },
+ {
+ id: "status",
+ content: (
+ handleSort(e, "status")}
+ sx={{ cursor: "pointer" }}
+ >
+ {t("common.table.headers.status")}
+ {renderSortIcon(sortField === "status")}
+
+ ),
+ render: (row) => {
+ return ;
+ },
+ },
+ {
+ id: "histogram",
+ content: t("pages.pageSpeed.table.headers.pageSpeedScore"),
+ render: (row) => {
+ return (
+
+
+
+ );
+ },
+ },
+
+ {
+ id: "actions",
+ content: t("common.table.headers.actions"),
+ render: (row) => {
+ return ;
+ },
+ },
+ ];
+ return headers;
+ };
+
+ let headers = getHeaders();
+
+ if (isSmall) {
+ headers = headers.filter((h) => h.id !== "histogram");
+ }
+ return (
+
+ {
+ navigate(`/pagespeed/${row.id}`);
+ }}
+ />
+
+
+ );
+};
diff --git a/client/src/Pages/PageSpeed/Monitors/index.tsx b/client/src/Pages/PageSpeed/Monitors/index.tsx
new file mode 100644
index 000000000..887ec02c0
--- /dev/null
+++ b/client/src/Pages/PageSpeed/Monitors/index.tsx
@@ -0,0 +1,117 @@
+import {
+ MonitorBasePageWithStates,
+ UpStatusBox,
+ DownStatusBox,
+ PausedStatusBox,
+ PageSpeedKeyPriorityFallback,
+} from "@/Components/v2/design-elements";
+import { Dialog } from "@/Components/v2/inputs";
+import { HeaderCreate } from "@/Components/v2/common";
+import Stack from "@mui/material/Stack";
+import { PageSpeedMonitorsTable } from "@/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable";
+import type { Monitor } from "@/Types/Monitor";
+
+import { useTheme } from "@mui/material";
+import { useTranslation } from "react-i18next";
+import { useState } from "react";
+import { useIsAdmin } from "@/Hooks/useIsAdmin";
+import { useGet, useDelete } from "@/Hooks/UseApi";
+import type { MonitorsWithChecksResponse } from "@/Types/Monitor";
+import type { AppSettingsResponse } from "@/Types/Settings";
+
+const PageSpeedMonitorsPage = () => {
+ const { t } = useTranslation();
+ const theme = useTheme();
+ const isAdmin = useIsAdmin();
+ const { deleteFn, loading: isDeleting } = useDelete();
+
+ const monitorsUrl = "/monitors/team/with-checks?type=pagespeed&limit=10";
+ const {
+ data: monitorsData,
+ isLoading: monitorsIsLoading,
+ error: monitorsError,
+ refetch,
+ } = useGet(monitorsUrl, {}, { refreshInterval: 30000 });
+
+ const settingsUrl = "/settings";
+ const {
+ data: settingsData,
+ isLoading: settingsIsLoading,
+ error: settingsError,
+ } = useGet(settingsUrl);
+
+ const [selectedMonitor, setSelectedMonitor] = useState(null);
+ const isDialogOpen = Boolean(selectedMonitor);
+ const [sortField, setSortField] = useState("name");
+ const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc");
+ const [page, setPage] = useState(0);
+ const [rowsPerPage, setRowsPerPage] = useState(10);
+
+ const monitors = monitorsData?.monitors;
+ const monitorsCount = monitorsData?.count;
+ const summary = monitorsData?.summary;
+
+ const isLoading = monitorsIsLoading || settingsIsLoading;
+
+ const showApiKeyWarning = isAdmin && settingsData && !settingsData.pagespeedKeySet;
+
+ const handleConfirm = async () => {
+ if (!selectedMonitor) return;
+ await deleteFn(`/monitors/${selectedMonitor.id}`);
+ setSelectedMonitor(null);
+ refetch();
+ };
+
+ const handleCancel = () => {
+ setSelectedMonitor(null);
+ };
+
+ return (
+ : undefined}
+ >
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default PageSpeedMonitorsPage;
diff --git a/client/src/Pages/PageSpeed/Monitors/index.jsx b/client/src/Pages/PageSpeed/Monitors/old.jsx
similarity index 100%
rename from client/src/Pages/PageSpeed/Monitors/index.jsx
rename to client/src/Pages/PageSpeed/Monitors/old.jsx
diff --git a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx
index 21e014688..c7f5c4c7f 100644
--- a/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx
+++ b/client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx
@@ -24,6 +24,7 @@ import type { RootState } from "@/Types/state";
export const MonitorTable = ({
monitors,
refetch,
+ setSelectedMonitor,
sortField,
setSortField,
sortOrder,
@@ -36,6 +37,7 @@ export const MonitorTable = ({
}: {
monitors: Monitor[];
refetch: Function;
+ setSelectedMonitor: (monitor: Monitor | null) => void;
sortField: string;
setSortField: (field: string) => void;
sortOrder: "asc" | "desc";
@@ -97,7 +99,7 @@ export const MonitorTable = ({
id: 4,
label: t("pages.common.monitors.actions.configure"),
action: () => {
- navigate(`/uptime/create/${monitor.id}`);
+ navigate(`/uptime/configure/${monitor.id}`);
},
},
// {
@@ -126,9 +128,7 @@ export const MonitorTable = ({
{t("pages.common.monitors.actions.delete")}
),
- action: () => {
- // setSelectedMonitor(monitor);
- },
+ action: () => setSelectedMonitor(monitor),
closeMenu: true,
},
];
diff --git a/client/src/Pages/Uptime/Monitors/index.tsx b/client/src/Pages/Uptime/Monitors/index.tsx
index e3e90429a..5c3828d07 100644
--- a/client/src/Pages/Uptime/Monitors/index.tsx
+++ b/client/src/Pages/Uptime/Monitors/index.tsx
@@ -5,14 +5,14 @@ import {
DownStatusBox,
PausedStatusBox,
} from "@/Components/v2/design-elements";
-import { TextField } from "@/Components/v2/inputs";
+import { TextField, Dialog } from "@/Components/v2/inputs";
import Stack from "@mui/material/Stack";
import { MonitorTable } from "@/Pages/Uptime/Monitors/Components/UptimeMonitorsTable";
import { HeaderCreate } from "@/Components/v2/common";
import { useTranslation } from "react-i18next";
import useMediaQuery from "@mui/material/useMediaQuery";
-import { useGet } from "@/Hooks/UseApi";
+import { useGet, useDelete } from "@/Hooks/UseApi";
import type { Monitor, MonitorType, MonitorsWithChecksResponse } from "@/Types/Monitor";
import { useState, useMemo, useCallback } from "react";
import { useSelector, useDispatch } from "react-redux";
@@ -40,6 +40,8 @@ const UptimeMonitorsPage = () => {
const [search, setSearch] = useState("");
const [sortField, setSortField] = useState("");
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc");
+ const [selectedMonitor, setSelectedMonitor] = useState(null);
+ const isDialogOpen = Boolean(selectedMonitor);
// Convert filter selections to API filter values
// Status: "up" -> true, "down" -> false
@@ -88,6 +90,7 @@ const UptimeMonitorsPage = () => {
data: monitors,
isLoading: monitorsLoading,
error,
+ refetch: refetchMonitorsAndSummary,
} = useGet(
"/monitors/team?type=http&type=ping&type=port&type=docker",
{},
@@ -107,6 +110,9 @@ const UptimeMonitorsPage = () => {
const { monitors: monitorsWithChecks, summary, count } = monitorsWithChecksData ?? {};
+ // Delete hook
+ const { deleteFn, loading: isDeleting } = useDelete();
+
// Handlers
const handleClearFilters = useCallback(() => {
setSelectedTypes([]);
@@ -115,6 +121,18 @@ const UptimeMonitorsPage = () => {
setSearch("");
}, []);
+ const handleConfirm = async () => {
+ if (!selectedMonitor) return;
+ await deleteFn(`/monitors/${selectedMonitor.id}`);
+ setSelectedMonitor(null);
+ refetch();
+ refetchMonitorsAndSummary();
+ };
+
+ const handleCancel = () => {
+ setSelectedMonitor(null);
+ };
+
const isLoading = monitorsLoading || monitorsWithChecksLoading;
return (
@@ -164,6 +182,7 @@ const UptimeMonitorsPage = () => {
{
sortOrder={sortOrder}
setSortOrder={setSortOrder}
setRowsPerPage={(rowsPerPage: number) => {
- console.log("wtf");
dispatch(
setRowsPerPage({
value: rowsPerPage,
@@ -183,6 +201,14 @@ const UptimeMonitorsPage = () => {
setPage(0);
}}
/>
+
);
};
diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx
index 715d4374e..c9a1084d6 100644
--- a/client/src/Routes/index.jsx
+++ b/client/src/Routes/index.jsx
@@ -20,7 +20,7 @@ import UptimeDetails from "../Pages/Uptime/Details";
import UptimeCreate from "../Pages/Uptime/Create/index.jsx";
// PageSpeed
-import PageSpeed from "../Pages/PageSpeed/Monitors/index.jsx";
+import PageSpeed from "../Pages/PageSpeed/Monitors/index";
import PageSpeedDetails from "../Pages/PageSpeed/Details/index.jsx";
import PageSpeedCreate from "../Pages/PageSpeed/Create/index.jsx";
@@ -63,6 +63,7 @@ import Logs from "../Pages/Logs/index.jsx";
const Routes = () => {
const mode = useSelector((state) => state.ui.mode);
const AdminCheckedRegister = withAdminCheck(AuthRegister);
+ const v2theme = mode === "light" ? lightTheme : darkTheme;
return (
{
path="/uptime"
element={
<>
-
+
>
@@ -105,7 +106,7 @@ const Routes = () => {
path="/uptime/:monitorId/"
element={
<>
-
+
>
@@ -118,7 +119,13 @@ const Routes = () => {
}
+ element={
+ <>
+
+
+
+ >
+ }
/>
Settings to add one. Without it, the PageSpeed monitor won't function."
+ }
+ },
+ "dialogs": {
+ "delete": {
+ "description": "This action cannot be undone.",
+ "title": "Are you sure you want to delete this?"
+ }
},
"toasts": {
"networkError": "Network error",
@@ -216,6 +232,13 @@
"statusCode": "Status code"
}
}
+ },
+ "pageSpeed": {
+ "table": {
+ "headers": {
+ "pageSpeedScore": "PageSpeed score"
+ }
+ }
}
},
"distributedUptimeStatusCreateStatusPage": "status page",
diff --git a/server/src/service/business/monitorService.ts b/server/src/service/business/monitorService.ts
index 513fc2a82..38fcaef78 100644
--- a/server/src/service/business/monitorService.ts
+++ b/server/src/service/business/monitorService.ts
@@ -342,7 +342,7 @@ export class MonitorService implements IMonitorService {
order?: "asc" | "desc";
explain?: boolean;
}): Promise => {
- const summary = await this.monitorsRepository.findMonitorsSummaryByTeamId(teamId);
+ const summary = await this.monitorsRepository.findMonitorsSummaryByTeamId(teamId, { type });
const count = await this.monitorsRepository.findMonitorCountByTeamIdAndType(teamId, { type, filter });
const monitors = await this.monitorsRepository.findByTeamId(teamId, {
limit,
@@ -402,9 +402,27 @@ export class MonitorService implements IMonitorService {
deleteMonitor = async ({ teamId, monitorId }: { teamId: string; monitorId: string }): Promise => {
const monitor = await this.monitorsRepository.deleteById(monitorId, teamId);
- await this.monitorStatsRepository.deleteByMonitorId(monitor.id);
- await this.checksRepository.deleteByMonitorId(monitor.id);
- await this.statusPagesRepository.removeMonitorFromStatusPages(monitor.id);
+ await this.monitorStatsRepository.deleteByMonitorId(monitor.id).catch((err: any) => {
+ this.logger.warn({
+ message: `Error deleting monitor stats for monitor ${monitor.id} with name ${monitor.name}`,
+ service: SERVICE_NAME,
+ stack: err.stack,
+ });
+ });
+ await this.checksRepository.deleteByMonitorId(monitor.id).catch((err: any) => {
+ this.logger.warn({
+ message: `Error deleting checks for monitor ${monitor.id} with name ${monitor.name}`,
+ service: SERVICE_NAME,
+ stack: err.stack,
+ });
+ });
+ await this.statusPagesRepository.removeMonitorFromStatusPages(monitor.id).catch((err: any) => {
+ this.logger.warn({
+ message: `Error removing monitor ${monitor.id} with name ${monitor.name} from status pages`,
+ service: SERVICE_NAME,
+ stack: err.stack,
+ });
+ });
await this.jobQueue.deleteJob(monitor);
return monitor;
};