feat: add LocationResult type and locationResults to Check model
## Changes - Add LocationResult interface to server check types - Add locationResults optional field to Check interface - Add GlobalpingCheckResult interface to network types - Add locationResultSchema subdocument and locationResults field to Mongoose Check schema - Fix formatting in pre-existing files (SettingsGlobalping, Settings index, UptimeMonitorsTable, monitorService) ## Benefits Non-destructive addition of the data model needed to store per-location Globalping results inside a single Check document. No existing behaviour is changed.
This commit is contained in:
1 parent
b7c9e2710a
commit
d25ce9e498
11 files changed
+87
-44
No files matched your search
@@ -113,10 +113,16 @@ const SettingsGlobalping = ({
|
||||
control={<Radio sx={{ p: 0, mr: theme.spacing(4) }} />}
|
||||
label={
|
||||
<Box>
|
||||
<Typography fontWeight={500} lineHeight={1.5}>
|
||||
<Typography
|
||||
fontWeight={500}
|
||||
lineHeight={1.5}
|
||||
>
|
||||
{t(`pages.settings.globalpingSettings.${tier.labelKey}`)}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
{t(`pages.settings.globalpingSettings.${tier.descKey}`)}
|
||||
</Typography>
|
||||
</Box>
|
||||
@@ -145,18 +151,30 @@ const SettingsGlobalping = ({
|
||||
<Typography sx={{ mb: theme.spacing(4) }}>
|
||||
{t("pages.settings.globalpingSettings.rateLimitsDescription")}
|
||||
</Typography>
|
||||
<Box component="ul" sx={{ m: 0, pl: theme.spacing(8) }}>
|
||||
<Typography component="li" sx={{ mb: theme.spacing(2) }}>
|
||||
<Box
|
||||
component="ul"
|
||||
sx={{ m: 0, pl: theme.spacing(8) }}
|
||||
>
|
||||
<Typography
|
||||
component="li"
|
||||
sx={{ mb: theme.spacing(2) }}
|
||||
>
|
||||
{t("pages.settings.globalpingSettings.rateLimitNoAuth")}
|
||||
</Typography>
|
||||
<Typography component="li" sx={{ mb: theme.spacing(2) }}>
|
||||
<Typography
|
||||
component="li"
|
||||
sx={{ mb: theme.spacing(2) }}
|
||||
>
|
||||
{t("pages.settings.globalpingSettings.rateLimitAuth")}
|
||||
</Typography>
|
||||
<Typography component="li">
|
||||
{t("pages.settings.globalpingSettings.rateLimitSponsor")}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography color="text.secondary" sx={{ mt: theme.spacing(4), fontStyle: "italic" }}>
|
||||
<Typography
|
||||
color="text.secondary"
|
||||
sx={{ mt: theme.spacing(4), fontStyle: "italic" }}
|
||||
>
|
||||
{t("pages.settings.globalpingSettings.rateLimitsNote")}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -120,7 +120,11 @@ const Settings = () => {
|
||||
if (isGlobalpingKeySet && !globalpingKeyHasBeenReset && !toSubmit.globalpingApiKey) {
|
||||
delete toSubmit.globalpingApiKey;
|
||||
}
|
||||
if (isEmailPasswordSet && !emailPasswordHasBeenReset && !toSubmit.systemEmailPassword) {
|
||||
if (
|
||||
isEmailPasswordSet &&
|
||||
!emailPasswordHasBeenReset &&
|
||||
!toSubmit.systemEmailPassword
|
||||
) {
|
||||
delete toSubmit.systemEmailPassword;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,9 @@ const UptimeDetailsPage = () => {
|
||||
const checks = checksData?.checks ?? [];
|
||||
const checksCount = checksData?.checksCount ?? 0;
|
||||
|
||||
const globalpingLocationsUrl = monitor?.globalpingEnabled ? "/monitors/globalping/locations" : null;
|
||||
const globalpingLocationsUrl = monitor?.globalpingEnabled
|
||||
? "/monitors/globalping/locations"
|
||||
: null;
|
||||
const { data: globalpingData } = useGet<{
|
||||
locations: { id: string; label: string }[];
|
||||
labels: Record<string, string>;
|
||||
|
||||
@@ -177,7 +177,10 @@ export const MonitorTable = ({
|
||||
{row?.name}
|
||||
{row.globalpingEnabled && (
|
||||
<Tooltip title={t("pages.uptime.table.headers.globalpingEnabled")}>
|
||||
<Globe size={14} aria-label={t("pages.uptime.table.headers.globalpingEnabled")} />
|
||||
<Globe
|
||||
size={14}
|
||||
aria-label={t("pages.uptime.table.headers.globalpingEnabled")}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -13,6 +13,7 @@ import type {
|
||||
CheckNetworkInterfaceInfo,
|
||||
GotTimings,
|
||||
ILighthouseAudit,
|
||||
LocationResult,
|
||||
} from "@/types/check.js";
|
||||
|
||||
type CheckMetadataDocument = Omit<CheckMetadata, "monitorId" | "teamId"> & {
|
||||
@@ -176,6 +177,17 @@ const auditsSchema = new Schema<CheckAudits>(
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const locationResultSchema = new Schema<LocationResult>(
|
||||
{
|
||||
location: { type: String, required: true },
|
||||
status: { type: Boolean, required: true },
|
||||
responseTime: { type: Number, required: true },
|
||||
statusCode: { type: Number, required: true },
|
||||
message: { type: String, default: "" },
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const metadataSchema = new Schema<CheckMetadataDocument>(
|
||||
{
|
||||
monitorId: {
|
||||
@@ -285,6 +297,10 @@ const CheckSchema = new Schema<CheckDocument>(
|
||||
type: auditsSchema,
|
||||
default: undefined,
|
||||
},
|
||||
locationResults: {
|
||||
type: [locationResultSchema],
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
|
||||
@@ -35,12 +35,7 @@ export interface IChecksRepository {
|
||||
options?: { type?: MonitorType }
|
||||
): Promise<UptimeChecksResult | HardwareChecksResult | PageSpeedChecksResult>;
|
||||
findSummaryByTeamId(teamId: string, dateRange: string): Promise<ChecksSummary>;
|
||||
findLocationChecksByMonitorId(
|
||||
monitorId: string,
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
dateString: string
|
||||
): Promise<Record<string, UptimeChecksResult>>;
|
||||
findLocationChecksByMonitorId(monitorId: string, startDate: Date, endDate: Date, dateString: string): Promise<Record<string, UptimeChecksResult>>;
|
||||
// update
|
||||
//delete
|
||||
deleteByMonitorId(monitorId: string): Promise<number>;
|
||||
|
||||
@@ -422,12 +422,7 @@ class MongoChecksRepository implements IChecksRepository {
|
||||
return result.deletedCount ?? 0;
|
||||
};
|
||||
|
||||
findLocationChecksByMonitorId = async (
|
||||
monitorId: string,
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
dateString: string
|
||||
): Promise<Record<string, any>> => {
|
||||
findLocationChecksByMonitorId = async (monitorId: string, startDate: Date, endDate: Date, dateString: string): Promise<Record<string, any>> => {
|
||||
const monitorObjectId = new mongoose.Types.ObjectId(monitorId);
|
||||
const matchStage = {
|
||||
"metadata.monitorId": monitorObjectId,
|
||||
@@ -469,8 +464,7 @@ class MongoChecksRepository implements IChecksRepository {
|
||||
|
||||
const locationChecks: Record<string, any> = {};
|
||||
for (const loc of results) {
|
||||
const uptimePercentage =
|
||||
loc.totalAllChecks > 0 ? loc.totalUpChecks / loc.totalAllChecks : 0;
|
||||
const uptimePercentage = loc.totalAllChecks > 0 ? loc.totalUpChecks / loc.totalAllChecks : 0;
|
||||
locationChecks[loc._id] = {
|
||||
groupedChecks: loc.groupedChecks,
|
||||
uptimePercentage,
|
||||
|
||||
@@ -226,12 +226,7 @@ export class MonitorService implements IMonitorService {
|
||||
// Fetch location checks if Globalping is enabled for this monitor
|
||||
let locationChecks: Record<string, LocationCheckData> | undefined;
|
||||
if (monitor.globalpingEnabled && (monitor.type === "http" || monitor.type === "ping")) {
|
||||
const locData = await this.checksRepository.findLocationChecksByMonitorId(
|
||||
monitor.id,
|
||||
start,
|
||||
end,
|
||||
this.getDateFormat(rangeKey)
|
||||
);
|
||||
const locData = await this.checksRepository.findLocationChecksByMonitorId(monitor.id, start, end, this.getDateFormat(rangeKey));
|
||||
if (Object.keys(locData).length > 0) {
|
||||
locationChecks = locData;
|
||||
}
|
||||
|
||||
@@ -179,27 +179,26 @@ class GlobalpingService {
|
||||
return [];
|
||||
}
|
||||
|
||||
const locations = locationIds
|
||||
.map((loc) => LOCATION_MAP[loc])
|
||||
.filter(Boolean);
|
||||
const locations = locationIds.map((loc) => LOCATION_MAP[loc]).filter(Boolean);
|
||||
|
||||
if (locations.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const createResult = measurementType === "http"
|
||||
? await client.createMeasurement({
|
||||
type: "http" as const,
|
||||
target,
|
||||
locations: locations as any,
|
||||
measurementOptions: { request: { method: "HEAD" }, protocol: "HTTPS" },
|
||||
})
|
||||
: await client.createMeasurement({
|
||||
type: "ping" as const,
|
||||
target,
|
||||
locations: locations as any,
|
||||
});
|
||||
const createResult =
|
||||
measurementType === "http"
|
||||
? await client.createMeasurement({
|
||||
type: "http" as const,
|
||||
target,
|
||||
locations: locations as any,
|
||||
measurementOptions: { request: { method: "HEAD" }, protocol: "HTTPS" },
|
||||
})
|
||||
: await client.createMeasurement({
|
||||
type: "ping" as const,
|
||||
target,
|
||||
locations: locations as any,
|
||||
});
|
||||
|
||||
if (!createResult.ok) {
|
||||
this.logger.warn({
|
||||
|
||||
@@ -9,6 +9,14 @@ export interface CheckMetadata {
|
||||
location?: string;
|
||||
}
|
||||
|
||||
export interface LocationResult {
|
||||
location: string;
|
||||
status: boolean;
|
||||
responseTime: number;
|
||||
statusCode: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface CheckCpuInfo {
|
||||
physical_core?: number;
|
||||
logical_core?: number;
|
||||
@@ -114,6 +122,7 @@ export interface Check {
|
||||
seo?: number;
|
||||
performance?: number;
|
||||
audits?: CheckAudits;
|
||||
locationResults?: LocationResult[];
|
||||
__v: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
||||
@@ -37,6 +37,14 @@ export interface MonitorStatusResponse<T = any> {
|
||||
location?: string;
|
||||
}
|
||||
|
||||
export interface GlobalpingCheckResult {
|
||||
location: string;
|
||||
status: boolean;
|
||||
responseTime: number;
|
||||
statusCode: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface PingStatusPayload {
|
||||
host: string;
|
||||
numeric_host?: string;
|
||||
|
||||
Reference in new issue
Block a user