check details base

This commit is contained in:
Alex Holliday committed 2025-12-19 15:12:30 -08:00
1 parent d139e0b643
commit 66c406151a
9 files changed
+112 -47

No files matched your search

+2 -1
View File
@@ -4,4 +4,5 @@
AGENTS.md
*.sh
notes
docker-compose.yml
docker-compose.yml
mongo
@@ -7,16 +7,42 @@ import type { StackProps } from "@mui/material/Stack";
import { useTheme } from "@mui/material/styles";
import { useTranslation } from "react-i18next";
interface BasePageProps extends StackProps {
loading?: boolean;
error?: boolean;
children: React.ReactNode;
breadcrumbOverride?: string[];
}
export const BasePage = ({
loading,
error,
children,
breadcrumbOverride,
...props
}: BasePageProps) => {
const theme = useTheme();
if (loading) {
return (
<Stack
alignItems="center"
justifyContent="center"
sx={{ height: "100%" }}
>
<CircularProgress color="primary" size={28} />
</Stack>
);
}
if (error) {
return (
<ErrorFallback
title="Something went wrong..."
subtitle="Please try again later"
/>
);
}
return (
<Stack spacing={theme.spacing(10)} {...props}>
<Breadcrumb breadcrumbOverride={breadcrumbOverride} />
@@ -49,27 +75,6 @@ export const BasePageWithStates = ({
}: BasePageWithStatesProps) => {
const showLoading = loading && (!items || items.length === 0);
if (showLoading) {
return (
<Stack
alignItems="center"
justifyContent="center"
sx={{ height: "100%" }}
>
<CircularProgress color="primary" size={28} />
</Stack>
);
}
if (error) {
return (
<ErrorFallback
title="Something went wrong..."
subtitle="Please try again later"
/>
);
}
if (isEmpty(items)) {
return (
<EmptyFallback
@@ -81,7 +86,11 @@ export const BasePageWithStates = ({
);
}
return <BasePage {...props}>{children}</BasePage>;
return (
<BasePage loading={showLoading} error={error} {...props}>
{children}
</BasePage>
);
};
interface MonitorBasePageWithStatesProps extends StackProps {
@@ -114,27 +123,6 @@ export const MonitorBasePageWithStates = ({
const showLoading = loading && (!items || items.length === 0);
if (showLoading) {
return (
<Stack
alignItems="center"
justifyContent="center"
sx={{ height: "100%" }}
>
<CircularProgress color="primary" size={28} />
</Stack>
);
}
if (error) {
return (
<ErrorFallback
title="Something went wrong..."
subtitle="Please try again later"
/>
);
}
if (isEmpty(items)) {
return (
<EmptyMonitorFallback
@@ -148,5 +136,9 @@ export const MonitorBasePageWithStates = ({
);
}
return <BasePage {...props}>{children}</BasePage>;
return (
<BasePage loading={showLoading} error={error} {...props}>
{children}
</BasePage>
);
};
+21
View File
@@ -0,0 +1,21 @@
import { BasePage } from "@/components/design-elements";
import { useParams } from "react-router";
import { useGet } from "@/hooks/UseApi";
import type { ICheck } from "@/types/check";
import type { ApiResponse } from "@/types/api";
const CheckDetails = () => {
const { id } = useParams();
const { response, loading, error } = useGet<ApiResponse<ICheck>>(
`/checks/${id}`
);
const check = response?.data;
return (
<BasePage loading={loading} error={error}>
{JSON.stringify(check)}
</BasePage>
);
};
export default CheckDetails;
+9 -1
View File
@@ -6,6 +6,7 @@ import type { ICheck, IChecksWithCount } from "@/types/check";
import type { ApiResponse } from "@/types/api";
import type { MonitorStatus } from "@/types/monitor";
import { useNavigate } from "react-router";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useGet } from "@/hooks/UseApi";
@@ -51,6 +52,7 @@ const getHeaders = (t: Function, uiTimezone: string) => {
};
export const CheckTable = ({ monitorId }: { monitorId: string }) => {
const navigate = useNavigate();
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const { t } = useTranslation();
@@ -87,7 +89,13 @@ export const CheckTable = ({ monitorId }: { monitorId: string }) => {
return (
<Box>
<Table headers={headers} data={checks} />
<Table
headers={headers}
data={checks}
onRowClick={(row) => {
navigate(`/checks/${row._id}`);
}}
/>
<Pagination
component="div"
count={count}
+1 -1
View File
@@ -119,7 +119,7 @@ const UptimeMonitors = () => {
return (
<MonitorBasePageWithStates
loading={loading}
loading={true}
error={error}
items={monitorItems}
page="uptime"
+2
View File
@@ -21,6 +21,7 @@ import NotificationChannelsConfigPage from "@/pages/notification-channels/Notifi
import IncidentsPage from "@/pages/incidents/IncidentsPage";
import IncidentDetailsPage from "@/pages/incidents/IncidentDetails";
import ChecksPage from "@/pages/checks/ChecksPage";
import CheckDetails from "@/pages/checks/CheckDetails";
import PageSpeedMonitorsPage from "@/pages/pagespeed/PageSpeedMonitors";
import PageSpeedDetailsPage from "@/pages/pagespeed/PageSpeedDetails";
import PageSpeedConfigurePage from "@/pages/pagespeed/PageSpeedConfig";
@@ -121,6 +122,7 @@ const Router = () => {
<Route path="incidents" element={<IncidentsPage />} />
<Route path="incidents/:id" element={<IncidentDetailsPage />} />
<Route path="checks" element={<ChecksPage />} />
<Route path="checks/:id" element={<CheckDetails />} />
<Route path="pagespeed/create" element={<PageSpeedCreatePage />} />
<Route
path="pagespeed/:id/configure"
@@ -4,6 +4,7 @@ import { CheckService } from "@/services/index.js";
export interface IChecksController {
getChecksByStatus: (req: Request, res: Response, next: NextFunction) => void;
getCheckById: (req: Request, res: Response, next: NextFunction) => void;
}
class ChecksController implements IChecksController {
@@ -53,6 +54,30 @@ class ChecksController implements IChecksController {
next(error);
}
};
getCheckById = async (req: Request, res: Response, next: NextFunction) => {
try {
const userContext = req.user;
if (!userContext) {
return res.status(401).json({ message: "Unauthorized" });
}
const teamId = userContext.currentTeamId;
if (!teamId) {
throw new ApiError("No team ID", 400);
}
const checkId = req.params.id;
const check = await this.checkService.getCheckById(checkId, teamId);
return res.status(200).json({
message: "Check retrieved successfully",
data: check,
});
} catch (error) {
next(error);
}
};
}
export default ChecksController;
+7
View File
@@ -26,6 +26,13 @@ class CheckRoutes {
validateQuery(checksStatusIdQuerySchema),
this.controller.getChecksByStatus
);
this.router.get(
"/:id",
verifyToken,
addUserContext,
verifyOrgPermission([PERMISSIONS.checks.read]),
this.controller.getCheckById
);
};
getRouter() {
@@ -33,6 +33,8 @@ export interface ICheckService {
range: string
) => Promise<{ checks: ICheck[]; count: number }>;
getCheckById: (checkId: string, teamId: string) => Promise<ICheck | null>;
cleanupOrphanedChecks: () => Promise<boolean>;
}
@@ -259,6 +261,13 @@ class CheckService implements ICheckService {
]);
return { checks, count };
};
getCheckById = async (checkId: string, teamId: string) => {
return await Check.findOne({
_id: new mongoose.Types.ObjectId(checkId),
"metadata.teamId": new mongoose.Types.ObjectId(teamId),
});
};
}
export default CheckService;