From dd44e6c34fe2f0f042c3416c5d87152c7e9070e5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 19 Aug 2026 10:20:21 -0700 Subject: [PATCH] add recent checks for infra monitors --- .../maintenance-window.service.ts | 4 +-- .../monitors/monitor.repository.interface.ts | 4 ++- .../monitors/monitor.repository.mongo.ts | 25 ++++++++++++++++--- .../status-pages/status-page.service.ts | 3 +-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/server/src/domain/maintenance-windows/maintenance-window.service.ts b/server/src/domain/maintenance-windows/maintenance-window.service.ts index dd27ba0b3..767e17699 100644 --- a/server/src/domain/maintenance-windows/maintenance-window.service.ts +++ b/server/src/domain/maintenance-windows/maintenance-window.service.ts @@ -106,7 +106,7 @@ export class MaintenanceWindowService implements IMaintenanceWindowService { start: string; end: string; }) => { - const monitors = await this.monitorsRepository.findByIds(monitorIDs, { includeRecentChecks: false }); + const monitors = await this.monitorsRepository.findByIds(monitorIDs, { recentChecks: "none" }); const unauthorizedMonitors = monitors.filter((monitor) => monitor.teamId !== teamId); @@ -193,7 +193,7 @@ export class MaintenanceWindowService implements IMaintenanceWindowService { const update: Partial = rest; if (monitors !== undefined) { - const monitorDocs = await this.monitorsRepository.findByIds(monitors, { includeRecentChecks: false }); + const monitorDocs = await this.monitorsRepository.findByIds(monitors, { recentChecks: "none" }); const unauthorizedMonitors = monitorDocs.filter((monitor) => monitor.teamId !== teamId); if (unauthorizedMonitors.length > 0) { throw new AppError({ diff --git a/server/src/domain/monitors/monitor.repository.interface.ts b/server/src/domain/monitors/monitor.repository.interface.ts index 53c178a1d..5528c97cf 100644 --- a/server/src/domain/monitors/monitor.repository.interface.ts +++ b/server/src/domain/monitors/monitor.repository.interface.ts @@ -16,6 +16,8 @@ export interface SummaryConfig { tags?: string | string[]; } +export type RecentChecksMode = "all" | "latestHardware" | "none"; + export interface IMonitorsRepository { // create create(monitor: Monitor, teamId: string, userId: string): Promise; @@ -29,7 +31,7 @@ export interface IMonitorsRepository { findAllForScheduling(): Promise; findByTeamId(teamId: string, config: TeamQueryConfig, options?: { includeRecentChecks?: boolean }): Promise; findByTeamIdWithStats(teamId: string, config: TeamQueryConfig): Promise; - findByIds(monitorIds: string[], options?: { includeRecentChecks?: boolean }): Promise; + findByIds(monitorIds: string[], options?: { recentChecks?: RecentChecksMode }): Promise; // update updateById(monitorId: string, teamId: string, updates: Partial): Promise; diff --git a/server/src/domain/monitors/monitor.repository.mongo.ts b/server/src/domain/monitors/monitor.repository.mongo.ts index 2411f3840..33c90dd59 100644 --- a/server/src/domain/monitors/monitor.repository.mongo.ts +++ b/server/src/domain/monitors/monitor.repository.mongo.ts @@ -5,7 +5,7 @@ import type { Monitor, MonitorScheduleFields, MonitorStatus, MonitorsSummary } f import mongoose, { type FilterQuery, type PipelineStage } from "mongoose"; import { MongoBulkWriteError } from "mongodb"; import { AppError } from "@/utils/AppError.js"; -import { IMonitorsRepository, TeamQueryConfig, SummaryConfig } from "@/domain/monitors/monitor.repository.interface.js"; +import { IMonitorsRepository, TeamQueryConfig, SummaryConfig, RecentChecksMode } from "@/domain/monitors/monitor.repository.interface.js"; import { toStringId, toDateString } from "@/utils/mongoMappers.js"; import { toCheckSnapshot } from "@/domain/checks/check.snapshot.js"; class MongoMonitorsRepository implements IMonitorsRepository { @@ -131,7 +131,26 @@ class MongoMonitorsRepository implements IMonitorsRepository { return documents.map((doc) => this.toEntity(doc)); }; - findByIds = async (monitorIds: string[], options?: { includeRecentChecks?: boolean }): Promise => { + private recentChecksStages = (mode: RecentChecksMode = "all"): PipelineStage[] => { + switch (mode) { + case "none": + return [{ $project: { recentChecks: 0 } }]; + case "latestHardware": + return [ + { + $set: { + recentChecks: { + $cond: [{ $eq: ["$type", "hardware"] }, { $slice: [{ $ifNull: ["$recentChecks", []] }, -1] }, []], + }, + }, + }, + ]; + case "all": + return []; + } + }; + + findByIds = async (monitorIds: string[], options?: { recentChecks?: "all" | "latestHardware" | "none" }): Promise => { if (!monitorIds.length) { return []; } @@ -140,7 +159,7 @@ class MongoMonitorsRepository implements IMonitorsRepository { const pipeline: PipelineStage[] = [ { $match: { _id: { $in: objectIds } } }, - ...(options?.includeRecentChecks === false ? [{ $project: { recentChecks: 0 } } as PipelineStage] : []), + ...this.recentChecksStages(options?.recentChecks), ...this.uptimeStatsLookupStages, ]; const documents = await MonitorModel.aggregate(pipeline); diff --git a/server/src/domain/status-pages/status-page.service.ts b/server/src/domain/status-pages/status-page.service.ts index 25e6d3e08..5f700857f 100644 --- a/server/src/domain/status-pages/status-page.service.ts +++ b/server/src/domain/status-pages/status-page.service.ts @@ -134,7 +134,7 @@ export class StatusPageService implements IStatusPageService { const dbSettings = await this.settingsService.getDBSettings(); const showURL = dbSettings.showURL; - const monitors = await this.monitorsRepository.findByIds(statusPage.monitors, { includeRecentChecks: range === "latest" }); + const monitors = await this.monitorsRepository.findByIds(statusPage.monitors, { recentChecks: range === "latest" ? "all" : "latestHardware" }); const order = new Map(statusPage.monitors.map((id, i) => [id, i])); const sorted = [...monitors].sort((a, b) => (order.get(a.id) ?? Number.MAX_SAFE_INTEGER) - (order.get(b.id) ?? Number.MAX_SAFE_INTEGER)); @@ -162,7 +162,6 @@ export class StatusPageService implements IStatusPageService { checkTTLDays: dbSettings.checkTTL, monitors: sorted.map((monitor) => ({ ...this.toPublicMonitor(monitor, showURL), - recentChecks: [], dailyChecks: bucketsByMonitor.get(monitor.id) ?? [], })), };