diff --git a/client/src/Pages/Uptime/Details/index.tsx b/client/src/Pages/Uptime/Details/index.tsx index d6ffc213c..061c4e0b1 100644 --- a/client/src/Pages/Uptime/Details/index.tsx +++ b/client/src/Pages/Uptime/Details/index.tsx @@ -116,8 +116,9 @@ const UptimeDetailsPage = () => { } const params = new URLSearchParams(); params.append("dateRange", dateRange); + params.append("continent", selectedLocation); return `/monitors/${monitorId}/geo-checks?${params.toString()}`; - }, [monitorId, monitor?.type, monitor?.geoCheckEnabled, dateRange]); + }, [monitorId, monitor?.type, monitor?.geoCheckEnabled, dateRange, selectedLocation]); const { data: _geoChecksData, isLoading: _geoChecksIsLoading } = useGet(geoChecksUrl, {}, { keepPreviousData: true }); diff --git a/server/src/controllers/monitorController.ts b/server/src/controllers/monitorController.ts index 07aa65361..662f35b50 100644 --- a/server/src/controllers/monitorController.ts +++ b/server/src/controllers/monitorController.ts @@ -27,6 +27,7 @@ import { } from "./controllerUtils.js"; import { AppError } from "@/utils/AppError.js"; import { IMonitorService } from "@/service/index.js"; +import { GeoContinent } from "@/types/geoCheck.js"; const SERVICE_NAME = "monitorController"; class MonitorController { @@ -141,12 +142,14 @@ class MonitorController { const monitorId = requireString(req?.params?.monitorId, "Monitor ID"); const dateRange = requireString(req?.query?.dateRange, "dateRange"); + const continent = optionalString(req?.query?.continent, "continent") as GeoContinent | undefined; const teamId = requireTeamId(req?.user?.teamId); const data = await this.monitorService.getGeoChecksByMonitorId({ teamId, monitorId, dateRange, + continent, }); return res.status(200).json({ diff --git a/server/src/repositories/geo-checks/IGeoChecksRepository.ts b/server/src/repositories/geo-checks/IGeoChecksRepository.ts index 9cba699ec..31b2dd2a5 100644 --- a/server/src/repositories/geo-checks/IGeoChecksRepository.ts +++ b/server/src/repositories/geo-checks/IGeoChecksRepository.ts @@ -1,9 +1,16 @@ import type { GeoCheck, GroupedGeoCheck } from "@/types/geoCheck.js"; +import type { GeoContinent } from "@/types/geoCheck.js"; export interface IGeoChecksRepository { createGeoChecks(geoChecks: Omit[]): Promise; findByMonitorIdAndDateRange(monitorId: string, startDate: Date, endDate: Date): Promise; - findGroupedByMonitorIdAndDateRange(monitorId: string, startDate: Date, endDate: Date, dateFormat: string): Promise; + findGroupedByMonitorIdAndDateRange( + monitorId: string, + startDate: Date, + endDate: Date, + dateFormat: string, + continent?: GeoContinent + ): Promise; deleteByMonitorId(monitorId: string): Promise; deleteByTeamId(teamId: string): Promise; } diff --git a/server/src/repositories/geo-checks/MongoGeoChecksRepository.ts b/server/src/repositories/geo-checks/MongoGeoChecksRepository.ts index 539f9addf..b40dc2cf8 100644 --- a/server/src/repositories/geo-checks/MongoGeoChecksRepository.ts +++ b/server/src/repositories/geo-checks/MongoGeoChecksRepository.ts @@ -117,7 +117,13 @@ class MongoGeoChecksRepository implements IGeoChecksRepository { } }; - findGroupedByMonitorIdAndDateRange = async (monitorId: string, startDate: Date, endDate: Date, dateFormat: string): Promise => { + findGroupedByMonitorIdAndDateRange = async ( + monitorId: string, + startDate: Date, + endDate: Date, + dateFormat: string, + continent?: string + ): Promise => { try { const pipeline: any[] = [ // Match geo checks for this monitor in date range @@ -134,6 +140,16 @@ class MongoGeoChecksRepository implements IGeoChecksRepository { { $unwind: "$results", }, + // Filter by continent if specified + ...(continent + ? [ + { + $match: { + "results.location.continent": continent, + }, + }, + ] + : []), // Group by date bucket and continent { $group: { diff --git a/server/src/service/business/monitorService.ts b/server/src/service/business/monitorService.ts index 157727755..2a1e9d0ed 100644 --- a/server/src/service/business/monitorService.ts +++ b/server/src/service/business/monitorService.ts @@ -8,6 +8,7 @@ import type { PageSpeedDetailsResult, GamesMap, } from "@/types/monitor.js"; +import type { GeoContinent } from "@/types/geoCheck.js"; import type { IChecksRepository, IGeoChecksRepository, @@ -37,7 +38,7 @@ export interface IMonitorService { getUptimeDetailsById(args: { teamId: string; monitorId: string; dateRange: string; normalize?: boolean }): Promise; getHardwareDetailsById(args: { teamId: string; monitorId: string; dateRange: string }): Promise; getPageSpeedDetailsById(args: { teamId: string; monitorId: string; dateRange: string }): Promise; - getGeoChecksByMonitorId(args: { teamId: string; monitorId: string; dateRange: string }): Promise; + getGeoChecksByMonitorId(args: { teamId: string; monitorId: string; dateRange: string; continent?: GeoContinent }): Promise; getMonitorById(args: { teamId: string; monitorId: string }): Promise; getMonitorsByTeamId(args: { teamId: string; @@ -322,7 +323,17 @@ export class MonitorService implements IMonitorService { }; }; - getGeoChecksByMonitorId = async ({ teamId, monitorId, dateRange }: { teamId: string; monitorId: string; dateRange: string }): Promise => { + getGeoChecksByMonitorId = async ({ + teamId, + monitorId, + dateRange, + continent, + }: { + teamId: string; + monitorId: string; + dateRange: string; + continent?: GeoContinent; + }): Promise => { const monitor = await this.monitorsRepository.findById(monitorId, teamId); if (!monitor) { throw new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 }); @@ -334,7 +345,13 @@ export class MonitorService implements IMonitorService { const rangeKey = (dateRange as DateRangeKey) ?? "recent"; const { start, end } = this.getDateRange(rangeKey); - const groupedGeoChecks = await this.geoChecksRepository.findGroupedByMonitorIdAndDateRange(monitor.id, start, end, this.getDateFormat(rangeKey)); + const groupedGeoChecks = await this.geoChecksRepository.findGroupedByMonitorIdAndDateRange( + monitor.id, + start, + end, + this.getDateFormat(rangeKey), + continent + ); return { groupedGeoChecks }; }; diff --git a/server/src/validation/joi.ts b/server/src/validation/joi.ts index 16aaa34a9..34283f461 100755 --- a/server/src/validation/joi.ts +++ b/server/src/validation/joi.ts @@ -113,6 +113,7 @@ const getMonitorByIdQueryValidation = joi.object({ dateRange: joi.string().valid("recent", "hour", "day", "week", "month", "all"), numToDisplay: joi.number(), normalize: joi.boolean(), + continent: joi.string().valid(...GeoContinents), }); const getMonitorsByTeamIdParamValidation = joi.object({});