refactor service
This commit is contained in:
1 parent
82cb59ae9e
commit
56aa7b3e1a
21 files changed
+301
-162
No files matched your search
@@ -70,7 +70,7 @@ const DockerMonitorsPage = () => {
|
||||
const monitorLimitReached = useLimitReached("monitorsMax", count);
|
||||
|
||||
const handleConfirm = async () => {
|
||||
await deleteFn(`/monitors/${selectedMonitor?._id}`);
|
||||
await deleteFn(`/monitors/${selectedMonitor?.id}`);
|
||||
setSelectedMonitor(null);
|
||||
refetch();
|
||||
};
|
||||
|
||||
@@ -58,17 +58,17 @@ export const DockerMonitorsTable = ({
|
||||
{
|
||||
id: 2,
|
||||
label: t("monitors.common.actions.details"),
|
||||
action: () => navigate(`/docker/${monitor._id}`),
|
||||
action: () => navigate(`/docker/${monitor.id}`),
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: t("monitors.common.actions.incidents"),
|
||||
action: () => navigate(`/incidents?monitorId=${monitor._id}`),
|
||||
action: () => navigate(`/incidents?monitorId=${monitor.id}`),
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: t("monitors.common.actions.configure"),
|
||||
action: () => navigate(`/docker/${monitor._id}/configure`),
|
||||
action: () => navigate(`/docker/${monitor.id}/configure`),
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
@@ -77,7 +77,7 @@ export const DockerMonitorsTable = ({
|
||||
? t("common.buttons.resume")
|
||||
: t("common.buttons.pause"),
|
||||
action: async () => {
|
||||
await patch(`/monitors/${monitor._id}/active`);
|
||||
await patch(`/monitors/${monitor.id}/active`);
|
||||
refetch();
|
||||
},
|
||||
closeMenu: true,
|
||||
@@ -124,7 +124,7 @@ export const DockerMonitorsTable = ({
|
||||
),
|
||||
render: (row) => {
|
||||
const containerCount = (
|
||||
checksMap[row._id]?.[0]?.dockerContainers || []
|
||||
checksMap[row.id]?.[0]?.dockerContainers || []
|
||||
).filter((c: any) => c?.running).length;
|
||||
return containerCount;
|
||||
},
|
||||
@@ -145,7 +145,7 @@ export const DockerMonitorsTable = ({
|
||||
<Table
|
||||
headers={headers}
|
||||
data={monitors}
|
||||
onRowClick={(row) => navigate(`/docker/${row._id}`)}
|
||||
onRowClick={(row) => navigate(`/docker/${row.id}`)}
|
||||
/>
|
||||
<Pagination
|
||||
component="div"
|
||||
|
||||
@@ -70,7 +70,7 @@ const InfraMonitorsPage = () => {
|
||||
const monitorLimitReached = useLimitReached("monitorsMax", count);
|
||||
|
||||
const handleConfirm = async () => {
|
||||
await deleteFn(`/monitors/${selectedMonitor?._id}`);
|
||||
await deleteFn(`/monitors/${selectedMonitor?.id}`);
|
||||
setSelectedMonitor(null);
|
||||
refetch();
|
||||
};
|
||||
|
||||
@@ -97,21 +97,21 @@ export const InfraMonitorsTable = ({
|
||||
id: 2,
|
||||
label: t("monitors.common.actions.details"),
|
||||
action: () => {
|
||||
navigate(`${monitor._id}`);
|
||||
navigate(`${monitor.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: t("monitors.common.actions.incidents"),
|
||||
action: () => {
|
||||
navigate(`/incidents?monitorId=${monitor._id}`);
|
||||
navigate(`/incidents?monitorId=${monitor.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: t("monitors.common.actions.configure"),
|
||||
action: () => {
|
||||
navigate(`/infrastructure/${monitor._id}/configure`);
|
||||
navigate(`/infrastructure/${monitor.id}/configure`);
|
||||
},
|
||||
},
|
||||
// {
|
||||
@@ -128,7 +128,7 @@ export const InfraMonitorsTable = ({
|
||||
? t("common.buttons.resume")
|
||||
: t("common.buttons.pause"),
|
||||
action: async () => {
|
||||
await patch(`/monitors/${monitor._id}/active`);
|
||||
await patch(`/monitors/${monitor.id}/active`);
|
||||
refetch();
|
||||
},
|
||||
closeMenu: true,
|
||||
@@ -208,7 +208,7 @@ export const InfraMonitorsTable = ({
|
||||
content: t("monitors.infrastructure.table.headers.cpu"),
|
||||
render: (row) => {
|
||||
const cpuUsage =
|
||||
(checksMap[row._id]?.[0]?.system?.cpu?.usage_percent || 0) * 100;
|
||||
(checksMap[row.id]?.[0]?.system?.cpu?.usage_percent || 0) * 100;
|
||||
return <Gauge progress={cpuUsage} />;
|
||||
},
|
||||
},
|
||||
@@ -217,7 +217,7 @@ export const InfraMonitorsTable = ({
|
||||
content: t("monitors.infrastructure.table.headers.memory"),
|
||||
render: (row) => {
|
||||
const memoryUsage =
|
||||
(checksMap[row._id]?.[0]?.system?.memory?.usage_percent || 0) * 100;
|
||||
(checksMap[row.id]?.[0]?.system?.memory?.usage_percent || 0) * 100;
|
||||
return <Gauge progress={memoryUsage} />;
|
||||
},
|
||||
},
|
||||
@@ -225,11 +225,11 @@ export const InfraMonitorsTable = ({
|
||||
id: "disk",
|
||||
content: t("monitors.infrastructure.table.headers.disk"),
|
||||
render: (row) => {
|
||||
const totalDiskUsage = checksMap[row._id]?.[0]?.system?.disk?.reduce(
|
||||
const totalDiskUsage = checksMap[row.id]?.[0]?.system?.disk?.reduce(
|
||||
(acc, disk) => acc + disk.usage_percent,
|
||||
0
|
||||
);
|
||||
const diskCount = checksMap[row._id]?.[0]?.system?.disk?.length || 1;
|
||||
const diskCount = checksMap[row.id]?.[0]?.system?.disk?.length || 1;
|
||||
const diskUsage = ((totalDiskUsage || 0) / diskCount) * 100;
|
||||
return <Gauge progress={diskUsage} />;
|
||||
},
|
||||
@@ -257,7 +257,7 @@ export const InfraMonitorsTable = ({
|
||||
headers={headers}
|
||||
data={monitors}
|
||||
onRowClick={(row) => {
|
||||
navigate(`/infrastructure/${row._id}`);
|
||||
navigate(`/infrastructure/${row.id}`);
|
||||
}}
|
||||
/>
|
||||
<Pagination
|
||||
|
||||
@@ -98,21 +98,21 @@ export const PageSpeedMonitorTable = ({
|
||||
id: 2,
|
||||
label: t("monitors.common.actions.details"),
|
||||
action: () => {
|
||||
navigate(`${monitor._id}`);
|
||||
navigate(`${monitor.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: t("monitors.common.actions.incidents"),
|
||||
action: () => {
|
||||
navigate(`/incidents?monitorId=${monitor._id}`);
|
||||
navigate(`/incidents?monitorId=${monitor.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: t("monitors.common.actions.configure"),
|
||||
action: () => {
|
||||
navigate(`/pagespeed/${monitor._id}/configure`);
|
||||
navigate(`/pagespeed/${monitor.id}/configure`);
|
||||
},
|
||||
},
|
||||
// {
|
||||
@@ -129,7 +129,7 @@ export const PageSpeedMonitorTable = ({
|
||||
? t("common.buttons.resume")
|
||||
: t("common.buttons.pause"),
|
||||
action: async () => {
|
||||
await patch(`/monitors/${monitor._id}/active`);
|
||||
await patch(`/monitors/${monitor.id}/active`);
|
||||
refetch();
|
||||
},
|
||||
closeMenu: true,
|
||||
@@ -207,7 +207,7 @@ export const PageSpeedMonitorTable = ({
|
||||
return (
|
||||
<Stack alignItems={"center"}>
|
||||
<HistogramPageSpeed
|
||||
checks={checksMap[row._id] ?? []}
|
||||
checks={checksMap[row.id] ?? []}
|
||||
status={row.status}
|
||||
/>
|
||||
</Stack>
|
||||
@@ -237,7 +237,7 @@ export const PageSpeedMonitorTable = ({
|
||||
headers={headers}
|
||||
data={monitors}
|
||||
onRowClick={(row) => {
|
||||
navigate(`/pagespeed/${row._id}`);
|
||||
navigate(`/pagespeed/${row.id}`);
|
||||
}}
|
||||
/>
|
||||
<Pagination
|
||||
|
||||
@@ -71,7 +71,7 @@ const PageSpeedMonitorsPage = () => {
|
||||
const monitorLimitReached = useLimitReached("monitorsMax", count);
|
||||
|
||||
const handleConfirm = async () => {
|
||||
await deleteFn(`/monitors/${selectedMonitor?._id}`);
|
||||
await deleteFn(`/monitors/${selectedMonitor?.id}`);
|
||||
setSelectedMonitor(null);
|
||||
refetch();
|
||||
};
|
||||
|
||||
@@ -155,7 +155,7 @@ const UptimeDetailsPage = () => {
|
||||
<ChartAvgResponse avg={avgResponseTime} max={maxResponseTime} />
|
||||
</Stack>
|
||||
<ChartResponseTime checks={checksAll} range={range} />
|
||||
<CheckTable monitorId={monitor?._id} />
|
||||
<CheckTable monitorId={monitor?.id} />
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -97,7 +97,7 @@ const UptimeMonitors = () => {
|
||||
const monitorLimitReached = useLimitReached("monitorsMax", count);
|
||||
|
||||
const handleConfirm = async () => {
|
||||
await deleteFn(`/monitors/${selectedMonitor?._id}`);
|
||||
await deleteFn(`/monitors/${selectedMonitor?.id}`);
|
||||
setSelectedMonitor(null);
|
||||
refetch();
|
||||
};
|
||||
|
||||
@@ -102,21 +102,21 @@ export const MonitorTable = ({
|
||||
id: 2,
|
||||
label: t("monitors.common.actions.details"),
|
||||
action: () => {
|
||||
navigate(`${monitor._id}`);
|
||||
navigate(`${monitor.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: t("monitors.common.actions.incidents"),
|
||||
action: () => {
|
||||
navigate(`/incidents?monitorId=${monitor._id}`);
|
||||
navigate(`/incidents?monitorId=${monitor.id}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: t("monitors.common.actions.configure"),
|
||||
action: () => {
|
||||
navigate(`/uptime/${monitor._id}/configure`);
|
||||
navigate(`/uptime/${monitor.id}/configure`);
|
||||
},
|
||||
},
|
||||
// {
|
||||
@@ -133,7 +133,7 @@ export const MonitorTable = ({
|
||||
? t("common.buttons.resume")
|
||||
: t("common.buttons.pause"),
|
||||
action: async () => {
|
||||
await patch(`/monitors/${monitor._id}/active`);
|
||||
await patch(`/monitors/${monitor.id}/active`);
|
||||
refetch();
|
||||
},
|
||||
closeMenu: true,
|
||||
@@ -209,9 +209,9 @@ export const MonitorTable = ({
|
||||
content: t("monitors.uptime.table.headers.responseTime"),
|
||||
render: (row) => {
|
||||
if (chartType === "histogram") {
|
||||
return <HistogramResponseTime checks={checksMap[row._id] ?? []} />;
|
||||
return <HistogramResponseTime checks={checksMap[row.id] ?? []} />;
|
||||
} else {
|
||||
return <HeatmapResponseTime checks={checksMap[row._id] ?? []} />;
|
||||
return <HeatmapResponseTime checks={checksMap[row.id] ?? []} />;
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -253,7 +253,7 @@ export const MonitorTable = ({
|
||||
headers={headers}
|
||||
data={monitors}
|
||||
onRowClick={(row) => {
|
||||
navigate(`/uptime/${row._id}`);
|
||||
navigate(`/uptime/${row.id}`);
|
||||
}}
|
||||
/>
|
||||
<Pagination
|
||||
|
||||
@@ -19,11 +19,13 @@ export const MonitorStatuses = [
|
||||
"down",
|
||||
"paused",
|
||||
"initializing",
|
||||
"resuming",
|
||||
] as const;
|
||||
|
||||
export type MonitorStatus = (typeof MonitorStatuses)[number];
|
||||
|
||||
export interface IMonitor {
|
||||
id: string;
|
||||
checks: ICheck[];
|
||||
createdAt: string;
|
||||
createdBy: string;
|
||||
@@ -47,7 +49,6 @@ export interface IMonitor {
|
||||
temperature: number;
|
||||
};
|
||||
__v: number;
|
||||
_id: string;
|
||||
}
|
||||
|
||||
export interface IMonitorWithStats {
|
||||
|
||||
@@ -21,6 +21,7 @@ export const getStatusPalette = (status: MonitorStatus): PaletteKey => {
|
||||
down: "error",
|
||||
paused: "warning",
|
||||
initializing: "warning",
|
||||
resuming: "warning",
|
||||
};
|
||||
return paletteMap[status];
|
||||
};
|
||||
@@ -40,6 +41,7 @@ export const getStatusColor = (status: MonitorStatus, theme: any): string => {
|
||||
down: theme.palette.error.light,
|
||||
paused: theme.palette.warning.light,
|
||||
initializing: theme.palette.warning.light,
|
||||
resuming: theme.palette.warning.light,
|
||||
};
|
||||
return statusColors[status];
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
} from "@/services/index.js";
|
||||
import { EntitlementsFactory } from "@/services/system/EntitlementsService.js";
|
||||
import { MeService } from "@/services/index.js";
|
||||
import { MongoMonitorRepository } from "@/repositories/index.js";
|
||||
|
||||
export const initServices = async () => {
|
||||
const checkService = new CheckService();
|
||||
@@ -71,7 +72,8 @@ export const initServices = async () => {
|
||||
const entitlementsProvider = EntitlementsFactory.create();
|
||||
const authService = new AuthService(jobQueue, entitlementsProvider);
|
||||
const meService = new MeService(entitlementsProvider);
|
||||
const monitorService = new MonitorService(jobQueue);
|
||||
const monitorRepository = new MongoMonitorRepository();
|
||||
const monitorService = new MonitorService(jobQueue, monitorRepository);
|
||||
const queueService = new QueueService(jobQueue);
|
||||
const teamService = new TeamService(jobQueue);
|
||||
const roleService = new RoleService();
|
||||
|
||||
Whitespace-only changes.
@@ -1,58 +0,0 @@
|
||||
import { Check } from "@/db/models/index.js";
|
||||
import type { ICheck } from "@/db/models/index.js";
|
||||
import type { IChecksRepository } from "@/repositories/checks/IChecksRepository.js";
|
||||
import { CheckEntity } from "@/types/domain/check.js";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
export class MongoChecksRepository implements IChecksRepository {
|
||||
private toEntity = (check: ICheck): CheckEntity => {
|
||||
return {
|
||||
id: check._id.toString(),
|
||||
metadata: {
|
||||
monitorId: check.metadata.monitorId.toString(),
|
||||
teamId: check.metadata.teamId.toString(),
|
||||
type: check.metadata.type,
|
||||
},
|
||||
status: check.status,
|
||||
httpStatusCode: check.httpStatusCode,
|
||||
message: check.message,
|
||||
timings: check.timings,
|
||||
errorMessage: check.errorMessage,
|
||||
ackAt: check.ackAt,
|
||||
ackBy: check.ackBy?.toString(),
|
||||
system: check.system,
|
||||
capture: check.capture,
|
||||
lighthouse: check.lighthouse,
|
||||
dockerContainers: check.dockerContainers,
|
||||
createdAt: check.createdAt,
|
||||
updatedAt: check.updatedAt,
|
||||
expiry: check.expiry,
|
||||
};
|
||||
};
|
||||
|
||||
findLatestByMonitorIds = async (monitorIds: string[]) => {
|
||||
const checks = await Check.aggregate([
|
||||
{
|
||||
$match: {
|
||||
"metadata.monitorId": {
|
||||
$in: monitorIds.map((id) => new mongoose.Types.ObjectId(id)),
|
||||
},
|
||||
},
|
||||
},
|
||||
{ $sort: { createdAt: -1 } },
|
||||
{
|
||||
$group: {
|
||||
_id: "$metadata.monitorId",
|
||||
latestChecks: { $push: "$$ROOT" },
|
||||
},
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
latestChecks: { $slice: [{ $ifNull: ["$latestChecks", []] }, 25] },
|
||||
},
|
||||
},
|
||||
]);
|
||||
console.log(checks);
|
||||
return checks;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export type {
|
||||
IMonitorRepository,
|
||||
TeamQueryConfig,
|
||||
} from "@/repositories/monitors/IMonitorRepoistory.js";
|
||||
export { default as MongoMonitorRepository } from "@/repositories/monitors/MongoMonitorRepository.js";
|
||||
@@ -0,0 +1,41 @@
|
||||
import type {
|
||||
Monitor,
|
||||
MonitorType,
|
||||
MonitorStatus,
|
||||
} from "@/types/domain/monitor.js";
|
||||
|
||||
export interface TeamQueryConfig {
|
||||
search: string;
|
||||
sortField: string;
|
||||
sortOrder: string;
|
||||
page: number;
|
||||
rowsPerPage: number;
|
||||
type: MonitorType[];
|
||||
status: MonitorStatus[];
|
||||
}
|
||||
|
||||
export interface IMonitorRepository {
|
||||
// Single fetch
|
||||
findById(monitorId: string, teamId: string): Promise<Monitor | null>;
|
||||
|
||||
// Collection fetches
|
||||
findByTeamId(teamId: string): Promise<Monitor[]>;
|
||||
findByTeamIdWithConfig(
|
||||
teamId: string,
|
||||
config: TeamQueryConfig
|
||||
): Promise<Monitor[]>;
|
||||
|
||||
findMonitorCountsByTeamId(teamId: string): Promise<{
|
||||
total: number;
|
||||
upCount: number;
|
||||
downCount: number;
|
||||
pausedCount: number;
|
||||
}>;
|
||||
findByOrgId(orgId: string): Promise<Monitor[]>;
|
||||
|
||||
// Deletions
|
||||
deleteById(id: string): Promise<boolean>;
|
||||
deleteByOrgId(orgId: string): Promise<number>;
|
||||
}
|
||||
|
||||
export default IMonitorRepository;
|
||||
@@ -0,0 +1,126 @@
|
||||
import { Monitor, IMonitor } from "@/db/models/index.js";
|
||||
import { IMonitorRepository, TeamQueryConfig } from "@/repositories/index.js";
|
||||
import type { Monitor as MonitorEntity } from "@/types/domain/monitor.js";
|
||||
import mongoose from "mongoose";
|
||||
class MongoMonitorRepository implements IMonitorRepository {
|
||||
private toEntity = (monitor: IMonitor): MonitorEntity => {
|
||||
return {
|
||||
id: monitor._id.toString(),
|
||||
orgId: monitor.orgId.toString(),
|
||||
teamId: monitor.teamId.toString(),
|
||||
name: monitor.name,
|
||||
url: monitor.url,
|
||||
port: monitor.port,
|
||||
secret: monitor.secret,
|
||||
type: monitor.type,
|
||||
interval: monitor.interval,
|
||||
rejectUnauthorized: monitor.rejectUnauthorized,
|
||||
status: monitor.status,
|
||||
n: monitor.n,
|
||||
thresholds: monitor.thresholds,
|
||||
lastCheckedAt: monitor.lastCheckedAt,
|
||||
latestStatuses: monitor.latestStatuses,
|
||||
notificationChannels: monitor.notificationChannels?.map((id) =>
|
||||
id.toString()
|
||||
),
|
||||
createdBy: monitor.createdBy.toString(),
|
||||
updatedBy: monitor.updatedBy.toString(),
|
||||
createdAt: monitor.createdAt,
|
||||
updatedAt: monitor.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
// Single fetch
|
||||
findById = async (monitorId: string, teamId: string) => {
|
||||
const monitor = await Monitor.findOne({ _id: monitorId, teamId });
|
||||
if (!monitor) return null;
|
||||
return this.toEntity(monitor);
|
||||
};
|
||||
|
||||
// Collection fetches
|
||||
findByTeamId = async (teamId: string) => {
|
||||
const monitors = await Monitor.find({ teamId });
|
||||
return monitors.map(this.toEntity);
|
||||
};
|
||||
|
||||
findByTeamIdWithConfig = async (teamId: string, config: TeamQueryConfig) => {
|
||||
if (!config) {
|
||||
const monitors = await Monitor.find({ teamId });
|
||||
return monitors.map(this.toEntity);
|
||||
}
|
||||
|
||||
const { search, sortField, sortOrder, page, rowsPerPage, type, status } =
|
||||
config;
|
||||
|
||||
const match: Record<string, unknown> = {
|
||||
teamId: new mongoose.Types.ObjectId(teamId),
|
||||
};
|
||||
|
||||
if (search && search.trim() !== "") {
|
||||
const term = search.trim();
|
||||
(match as any).$or = [
|
||||
{ name: { $regex: term, $options: "i" } },
|
||||
{ url: { $regex: term, $options: "i" } },
|
||||
];
|
||||
}
|
||||
|
||||
if (Array.isArray(type) && type.length > 0) {
|
||||
match.type = { $in: type };
|
||||
}
|
||||
|
||||
if (Array.isArray(status) && status.length > 0) {
|
||||
match.status = { $in: status };
|
||||
}
|
||||
|
||||
const skip = page * rowsPerPage;
|
||||
|
||||
const monitors = await Monitor.find(match)
|
||||
.sort({ [sortField]: sortOrder === "asc" ? 1 : -1 })
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage);
|
||||
|
||||
return monitors.map(this.toEntity);
|
||||
};
|
||||
findByOrgId = async (orgId: string) => {
|
||||
return [];
|
||||
};
|
||||
|
||||
findMonitorCountsByTeamId = async (teamId: string) => {
|
||||
const countResult = await Monitor.aggregate([
|
||||
{
|
||||
$match: { teamId: new mongoose.Types.ObjectId(teamId) },
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: null,
|
||||
total: { $sum: 1 },
|
||||
upCount: { $sum: { $cond: [{ $eq: ["$status", "up"] }, 1, 0] } },
|
||||
downCount: { $sum: { $cond: [{ $eq: ["$status", "down"] }, 1, 0] } },
|
||||
pausedCount: {
|
||||
$sum: {
|
||||
$cond: [{ $in: ["$status", ["paused", "resuming"]] }, 1, 0],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const counts = countResult[0] || {
|
||||
total: 0,
|
||||
upCount: 0,
|
||||
downCount: 0,
|
||||
pausedCount: 0,
|
||||
};
|
||||
return counts;
|
||||
};
|
||||
|
||||
// Deletions
|
||||
deleteById = async (id: string) => {
|
||||
return false;
|
||||
};
|
||||
deleteByOrgId = async (orgId: string) => {
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoMonitorRepository;
|
||||
@@ -8,6 +8,8 @@ import { MonitorWithChecksResponse } from "@/types/index.js";
|
||||
import { MonitorStatus, MonitorType } from "@/db/models/monitors/Monitor.js";
|
||||
import { Entitlements } from "@/types/entitlements.js";
|
||||
import { getStartDate } from "@/utils/TimeUtils.js";
|
||||
import { IMonitorRepository } from "@/repositories/index.js";
|
||||
import type { Monitor as MonitorEntity } from "@/types/domain/index.js";
|
||||
|
||||
export interface IImportedMonitor {
|
||||
name: string;
|
||||
@@ -44,7 +46,7 @@ export interface IMonitorService {
|
||||
currentTeamId: string,
|
||||
monitorData: IMonitor
|
||||
) => Promise<IMonitor>;
|
||||
getAll: (teamId: string) => Promise<IMonitor[]>;
|
||||
getAll: (teamId: string) => Promise<MonitorEntity[]>;
|
||||
getAllEmbedChecks: (
|
||||
teamId: string,
|
||||
search: string,
|
||||
@@ -61,7 +63,7 @@ export interface IMonitorService {
|
||||
pausedCount: number;
|
||||
monitors: any[];
|
||||
}>;
|
||||
get: (teamId: string, monitorId: string) => Promise<IMonitor>;
|
||||
get: (teamId: string, monitorId: string) => Promise<MonitorEntity>;
|
||||
getEmbedChecks: (
|
||||
teamId: string,
|
||||
monitorId: string,
|
||||
@@ -93,9 +95,11 @@ export interface IMonitorService {
|
||||
class MonitorService implements IMonitorService {
|
||||
public SERVICE_NAME: string;
|
||||
private jobQueue: IJobQueue;
|
||||
constructor(jobQueue: IJobQueue) {
|
||||
private monitorRepository: IMonitorRepository;
|
||||
constructor(jobQueue: IJobQueue, monitorRepository: IMonitorRepository) {
|
||||
this.SERVICE_NAME = SERVICE_NAME;
|
||||
this.jobQueue = jobQueue;
|
||||
this.monitorRepository = monitorRepository;
|
||||
}
|
||||
|
||||
create = async (
|
||||
@@ -122,7 +126,7 @@ class MonitorService implements IMonitorService {
|
||||
};
|
||||
|
||||
getAll = async (teamId: string) => {
|
||||
return Monitor.find({ teamId });
|
||||
return await this.monitorRepository.findByTeamId(teamId);
|
||||
};
|
||||
|
||||
getAllEmbedChecks = async (
|
||||
@@ -135,61 +139,24 @@ class MonitorService implements IMonitorService {
|
||||
type: MonitorType[] = [],
|
||||
status: MonitorStatus[] = []
|
||||
) => {
|
||||
const teamObjectId = new mongoose.Types.ObjectId(teamId);
|
||||
const counts = await this.monitorRepository.findMonitorCountsByTeamId(
|
||||
teamId
|
||||
);
|
||||
|
||||
const matchConditions: Record<string, unknown> = {
|
||||
teamId: teamObjectId,
|
||||
};
|
||||
|
||||
if (search && search.trim() !== "") {
|
||||
const term = search.trim();
|
||||
(matchConditions as any).$or = [
|
||||
{ name: { $regex: term, $options: "i" } },
|
||||
{ url: { $regex: term, $options: "i" } },
|
||||
];
|
||||
}
|
||||
|
||||
if (Array.isArray(type) && type.length > 0) {
|
||||
matchConditions.type = { $in: type };
|
||||
}
|
||||
|
||||
if (Array.isArray(status) && status.length > 0) {
|
||||
matchConditions.status = { $in: status };
|
||||
}
|
||||
|
||||
const countResult = await Monitor.aggregate([
|
||||
const monitors = await this.monitorRepository.findByTeamIdWithConfig(
|
||||
teamId,
|
||||
{
|
||||
$match: { teamId: teamObjectId },
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: null,
|
||||
total: { $sum: 1 },
|
||||
upCount: { $sum: { $cond: [{ $eq: ["$status", "up"] }, 1, 0] } },
|
||||
downCount: { $sum: { $cond: [{ $eq: ["$status", "down"] }, 1, 0] } },
|
||||
pausedCount: {
|
||||
$sum: { $cond: [{ $eq: ["$status", "paused"] }, 1, 0] },
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
search,
|
||||
sortField,
|
||||
sortOrder,
|
||||
page,
|
||||
rowsPerPage,
|
||||
type,
|
||||
status,
|
||||
}
|
||||
);
|
||||
|
||||
const counts = countResult[0] || {
|
||||
total: 0,
|
||||
upCount: 0,
|
||||
downCount: 0,
|
||||
pausedCount: 0,
|
||||
};
|
||||
|
||||
const skip = page * rowsPerPage;
|
||||
|
||||
const monitors = await Monitor.find(matchConditions)
|
||||
.lean()
|
||||
.sort({ [sortField]: sortOrder === "asc" ? 1 : -1 })
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage);
|
||||
|
||||
const monitorIds = monitors.map((m) => m._id);
|
||||
const monitorIds = monitors.map((m) => new mongoose.Types.ObjectId(m.id));
|
||||
|
||||
const checks = await Check.aggregate([
|
||||
{
|
||||
@@ -226,7 +193,7 @@ class MonitorService implements IMonitorService {
|
||||
};
|
||||
|
||||
get = async (teamId: string, monitorId: string) => {
|
||||
const monitor = await Monitor.findOne({ _id: monitorId, teamId });
|
||||
const monitor = await this.monitorRepository.findById(monitorId, teamId);
|
||||
if (!monitor) {
|
||||
throw new ApiError("Monitor not found", 404);
|
||||
}
|
||||
@@ -555,13 +522,16 @@ class MonitorService implements IMonitorService {
|
||||
return {};
|
||||
};
|
||||
|
||||
private getEmbedChecksRecent = async (monitor: IMonitor, startDate: Date) => {
|
||||
private getEmbedChecksRecent = async (
|
||||
monitor: MonitorEntity,
|
||||
startDate: Date
|
||||
) => {
|
||||
const endDate = new Date();
|
||||
const matchStage: {
|
||||
"metadata.monitorId": mongoose.Types.ObjectId;
|
||||
createdAt: { $gte: Date; $lt: Date };
|
||||
} = {
|
||||
"metadata.monitorId": monitor._id,
|
||||
"metadata.monitorId": new mongoose.Types.ObjectId(monitor.id),
|
||||
createdAt: { $gte: startDate, $lt: endDate },
|
||||
};
|
||||
|
||||
@@ -652,7 +622,7 @@ class MonitorService implements IMonitorService {
|
||||
|
||||
// Get monitor stats
|
||||
const monitorStats = await MonitorStats.findOne({
|
||||
monitorId: monitor._id,
|
||||
monitorId: monitor.id,
|
||||
});
|
||||
|
||||
if (!monitorStats) {
|
||||
@@ -660,19 +630,19 @@ class MonitorService implements IMonitorService {
|
||||
}
|
||||
|
||||
return {
|
||||
monitor: monitor.toObject(),
|
||||
monitor: monitor,
|
||||
checks,
|
||||
stats: monitorStats,
|
||||
};
|
||||
};
|
||||
|
||||
private getEmbedChecksOtherRanges = async (
|
||||
monitor: IMonitor,
|
||||
monitor: MonitorEntity,
|
||||
range: string,
|
||||
startDate: Date
|
||||
) => {
|
||||
const monitorStats = await MonitorStats.findOne({
|
||||
monitorId: monitor._id,
|
||||
monitorId: monitor.id,
|
||||
});
|
||||
if (!monitorStats) {
|
||||
throw new ApiError("Monitor stats not found", 404);
|
||||
@@ -683,7 +653,7 @@ class MonitorService implements IMonitorService {
|
||||
const endDate = new Date();
|
||||
|
||||
const docs = await Model.find({
|
||||
monitorId: monitor._id,
|
||||
monitorId: monitor.id,
|
||||
windowStart: { $gte: startDate, $lt: endDate },
|
||||
})
|
||||
.sort({ windowStart: -1 })
|
||||
@@ -739,7 +709,7 @@ class MonitorService implements IMonitorService {
|
||||
});
|
||||
|
||||
return {
|
||||
monitor: monitor.toObject(),
|
||||
monitor: monitor,
|
||||
checks,
|
||||
stats: monitorStats,
|
||||
};
|
||||
@@ -750,7 +720,7 @@ class MonitorService implements IMonitorService {
|
||||
monitorId: string,
|
||||
range: string
|
||||
): Promise<MonitorWithChecksResponse> => {
|
||||
const monitor = await Monitor.findOne({ _id: monitorId, teamId });
|
||||
const monitor = await this.monitorRepository.findById(monitorId, teamId);
|
||||
if (!monitor) {
|
||||
throw new ApiError("Monitor not found", 404);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export type { Monitor } from "@/types/domain/monitor.js";
|
||||
@@ -0,0 +1,49 @@
|
||||
export const MonitorTypes = [
|
||||
"http",
|
||||
"https",
|
||||
"port",
|
||||
"ping",
|
||||
"infrastructure",
|
||||
"pagespeed",
|
||||
"docker",
|
||||
] as const;
|
||||
export type MonitorType = (typeof MonitorTypes)[number];
|
||||
|
||||
export const MonitorStatuses = [
|
||||
"up",
|
||||
"down",
|
||||
"paused",
|
||||
"initializing",
|
||||
"resuming",
|
||||
] as const;
|
||||
export type MonitorStatus = (typeof MonitorStatuses)[number];
|
||||
|
||||
export interface MonitorThresholds {
|
||||
cpu?: number;
|
||||
memory?: number;
|
||||
disk?: number;
|
||||
temperature?: number;
|
||||
}
|
||||
|
||||
export interface Monitor {
|
||||
id: string;
|
||||
orgId: string;
|
||||
teamId: string;
|
||||
name: string;
|
||||
url: string;
|
||||
port?: number;
|
||||
secret?: string;
|
||||
type: MonitorType;
|
||||
interval: number; // in ms
|
||||
rejectUnauthorized: boolean;
|
||||
status: MonitorStatus;
|
||||
n: number; // Number of consecutive successes required to change status
|
||||
thresholds?: MonitorThresholds;
|
||||
lastCheckedAt?: Date;
|
||||
latestStatuses?: MonitorStatus[];
|
||||
notificationChannels?: string[];
|
||||
createdBy: string;
|
||||
updatedBy: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IMonitor, IMonitorStats } from "@/db/models/index.js";
|
||||
|
||||
import { IMonitorStats } from "@/db/models/index.js";
|
||||
import type { Monitor } from "@/types/domain/index.js";
|
||||
export interface MonitorWithChecksResponse {
|
||||
monitor: IMonitor;
|
||||
monitor: Monitor;
|
||||
checks: Array<{
|
||||
_id: string;
|
||||
count: number;
|
||||
|
||||
Reference in new issue
Block a user