Files
Checkmate/client/src/Hooks/useMonitorForm.ts
T
gorkem-bwl b7c9e2710a fix: address Globalping code review findings
## Changes

### Critical fixes
- Fix Switch `isChecked` → `checked` prop in CreateMonitor Globalping toggle
- Merge double `getDBSettings()` calls in globalpingService into single
  `getClientAndLocations()` method to eliminate redundant DB reads per check cycle
- Add in-flight lock (Set) to prevent overlapping Globalping checks for the same monitor
- Add hostname validation before calling Globalping API to prevent invalid targets

### Dead code removal
- Remove unused `locations` field from server Monitor type, Mongoose model,
  Joi validation, and repository mappers
- Remove unused `locations` field from client Monitor type
- Remove dead `getLimits()` method from globalpingService
- Remove dead `locations` translation keys from en.json
- Remove dead `monitorType`, `groupedUpChecks`, `groupedDownChecks` fields
  from findLocationChecksByMonitorId return value

### Medium/low fixes
- Make globalping/locations API fetch conditional on `monitor.globalpingEnabled`
  in Details page to avoid unnecessary requests
- Add useEffect to reset selectedLocationTab when location keys change
  to prevent out-of-bounds tab index
- Add `globalpingEnabled: false` to default case in useMonitorForm
- Replace console.log with comment in CreateMonitor onError handler
- Add aria-label to Globe icon for accessibility
- Add warning log when Globalping buildCheck returns undefined
- Fix step numbering in SuperSimpleQueueHelper (was duplicated Step 4)

## Benefits
- Eliminates one DB round-trip per monitor check cycle
- Prevents race conditions with overlapping Globalping checks
- Validates hostnames before external API calls
- Removes ~30 lines of dead code across server and client
- Improves accessibility with proper aria labels
2026-02-19 13:28:38 -05:00

112 lines
2.7 KiB
TypeScript

import { useMemo } from "react";
import { monitorSchema, type MonitorFormData } from "@/Validation/monitor";
import type { Monitor, MonitorType } from "@/Types/Monitor";
interface UseMonitorFormOptions {
data?: Monitor | null;
defaultType?: MonitorType;
}
const getBaseDefaults = (data?: Monitor | null) => ({
name: data?.name || "",
description: data?.description || "",
interval: data?.interval || 60000,
notifications: data?.notifications || [],
statusWindowSize: data?.statusWindowSize || 5,
statusWindowThreshold: data?.statusWindowThreshold || 60,
});
export const useMonitorForm = ({
data = null,
defaultType = "http",
}: UseMonitorFormOptions = {}) => {
return useMemo(() => {
const type = data?.type || defaultType;
const base = getBaseDefaults(data);
let defaults: MonitorFormData;
switch (type) {
case "http":
defaults = {
...base,
type: "http",
url: data?.url || "",
ignoreTlsErrors: data?.ignoreTlsErrors || false,
useAdvancedMatching: data?.useAdvancedMatching || false,
matchMethod: data?.matchMethod || "",
expectedValue: data?.expectedValue || "",
jsonPath: data?.jsonPath || "",
globalpingEnabled: data?.globalpingEnabled || false,
};
break;
case "ping":
defaults = {
...base,
type: "ping",
url: data?.url || "",
globalpingEnabled: data?.globalpingEnabled || false,
};
break;
case "port":
defaults = {
...base,
type: "port",
url: data?.url || "",
port: data?.port || 80,
};
break;
case "docker":
defaults = {
...base,
type: "docker",
url: data?.url || "",
};
break;
case "game":
defaults = {
...base,
type: "game",
url: data?.url || "",
port: data?.port || 27015,
gameId: data?.gameId || "",
};
break;
case "pagespeed":
defaults = {
...base,
type: "pagespeed",
url: data?.url || "",
};
break;
case "hardware":
defaults = {
...base,
type: "hardware",
url: data?.url || "",
secret: data?.secret || "",
cpuAlertThreshold: data?.cpuAlertThreshold ?? 100,
memoryAlertThreshold: data?.memoryAlertThreshold ?? 100,
diskAlertThreshold: data?.diskAlertThreshold ?? 100,
tempAlertThreshold: data?.tempAlertThreshold ?? 100,
selectedDisks: data?.selectedDisks || [],
};
break;
default:
defaults = {
...base,
type: "http",
url: "",
ignoreTlsErrors: false,
useAdvancedMatching: false,
matchMethod: "",
expectedValue: "",
jsonPath: "",
globalpingEnabled: false,
};
}
return { schema: monitorSchema, defaults };
}, [data, defaultType]);
};