From 8afd67a06d1e95b8a0c84dfb8ad171d6f4e159d3 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 22 Jun 2026 10:43:30 -0700 Subject: [PATCH 1/5] add method to monitor type --- client/src/Types/Monitor.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts index b2d90cb0b..fd9b521d5 100644 --- a/client/src/Types/Monitor.ts +++ b/client/src/Types/Monitor.ts @@ -48,6 +48,10 @@ export const PageSpeedStrategies = ["desktop", "mobile"] as const; export type PageSpeedStrategy = (typeof PageSpeedStrategies)[number]; export const DefaultPageSpeedStrategy: PageSpeedStrategy = "desktop"; +export const HttpMethods = ["GET", "HEAD"] as const; +export type HttpMethod = (typeof HttpMethods)[number]; +export const DefaultHttpMethod: HttpMethod = "GET"; + export interface Monitor { id: string; userId: string; @@ -64,6 +68,7 @@ export interface Monitor { jsonPath?: string; expectedValue?: string; matchMethod?: MonitorMatchMethod; + method?: HttpMethod; url: string; port?: number; isActive: boolean; From d84fc7e299cd68d667feb7157dc79ac9a20c2945 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 22 Jun 2026 10:48:39 -0700 Subject: [PATCH 2/5] add method to validation --- client/src/Validation/monitor.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/src/Validation/monitor.ts b/client/src/Validation/monitor.ts index e0c4eae07..a31cdb919 100644 --- a/client/src/Validation/monitor.ts +++ b/client/src/Validation/monitor.ts @@ -1,7 +1,12 @@ import { z } from "zod"; import type { FieldPath } from "react-hook-form"; import { GeoContinents } from "@/Types/GeoCheck"; -import { DnsRecordTypes, PageSpeedStrategies, type MonitorType } from "@/Types/Monitor"; +import { + DnsRecordTypes, + HttpMethods, + PageSpeedStrategies, + type MonitorType, +} from "@/Types/Monitor"; import { ALL_HTTP_STATUS_CODES } from "@/Utils/statusCode"; // Wizard step a field is validated on. Attached inline to each field below so @@ -62,6 +67,7 @@ const httpStatusCode = z.number().refine((code) => httpStatusCodeSet.has(code), const httpSchema = baseSchema.extend({ type: z.literal("http"), url: urlSchema, + method: z.enum(HttpMethods).optional().register(monitorStepRegistry, { step: 2 }), ignoreTlsErrors: z.boolean().register(monitorStepRegistry, { step: 2 }), useAdvancedMatching: z.boolean().register(monitorStepRegistry, { step: 2 }), matchMethod: z From a31dd2f19ea5610493d2caaaadad78a729c324f6 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 22 Jun 2026 11:07:56 -0700 Subject: [PATCH 3/5] update montior form hook to load method --- client/src/Hooks/useMonitorForm.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/Hooks/useMonitorForm.ts b/client/src/Hooks/useMonitorForm.ts index 0ae463911..9c6200d22 100644 --- a/client/src/Hooks/useMonitorForm.ts +++ b/client/src/Hooks/useMonitorForm.ts @@ -1,6 +1,6 @@ import { useMemo } from "react"; import { monitorSchema, type MonitorFormData } from "@/Validation/monitor"; -import { DefaultPageSpeedStrategy } from "@/Types/Monitor"; +import { DefaultHttpMethod, DefaultPageSpeedStrategy } from "@/Types/Monitor"; import type { Monitor, MonitorType } from "@/Types/Monitor"; interface UseMonitorFormOptions { @@ -40,6 +40,7 @@ export const getMonitorDefaults = ( ...getGeoCheckDefaults(data), type: "http", url: data?.url || "", + method: data?.method ?? DefaultHttpMethod, ignoreTlsErrors: data?.ignoreTlsErrors || false, useAdvancedMatching: data?.useAdvancedMatching || false, matchMethod: data?.matchMethod || "", @@ -134,6 +135,7 @@ export const getMonitorDefaults = ( ...getGeoCheckDefaults(data), type: "http", url: "", + method: DefaultHttpMethod, ignoreTlsErrors: false, useAdvancedMatching: false, matchMethod: "", From dead97169fccc0374da723e15f0f6910d75b4c54 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 22 Jun 2026 11:24:03 -0700 Subject: [PATCH 4/5] add default GET --- server/package-lock.json | 40 +++++++++++++++++-- .../monitors/monitor.repository.mongo.ts | 4 +- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/server/package-lock.json b/server/package-lock.json index 0fbe45e08..61dd35875 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1554,9 +1554,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, @@ -5200,6 +5200,40 @@ "node": ">=14.0.0" } }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", diff --git a/server/src/domain/monitors/monitor.repository.mongo.ts b/server/src/domain/monitors/monitor.repository.mongo.ts index d55fdd62d..cba542c96 100644 --- a/server/src/domain/monitors/monitor.repository.mongo.ts +++ b/server/src/domain/monitors/monitor.repository.mongo.ts @@ -536,7 +536,7 @@ class MongoMonitorsRepository implements IMonitorsRepository { teamId: toStringId(doc.teamId), name: doc.name, description: doc.description ?? undefined, - method: doc.method, + method: doc.method ?? "GET", status: doc.status ?? "initializing", statusWindow: doc.statusWindow ?? [], statusWindowSize: doc.statusWindowSize, @@ -603,7 +603,7 @@ class MongoMonitorsRepository implements IMonitorsRepository { teamId: toStringId(doc.teamId), name: doc.name, description: doc.description ?? undefined, - method: doc.method, + method: doc.method ?? "GET", status: doc.status ?? "initializing", statusWindow: doc.statusWindow ?? [], statusWindowSize: doc.statusWindowSize, From ba943e90c22bc05e71e6b869df07671d762b0c6a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 22 Jun 2026 11:24:35 -0700 Subject: [PATCH 5/5] add form UI --- client/src/Pages/CreateMonitor/index.tsx | 96 ++++++++++++++----- .../Components/UptimeMonitorsTable.tsx | 4 +- client/src/locales/en.json | 7 ++ 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/client/src/Pages/CreateMonitor/index.tsx b/client/src/Pages/CreateMonitor/index.tsx index 465b9d15d..96b05be71 100644 --- a/client/src/Pages/CreateMonitor/index.tsx +++ b/client/src/Pages/CreateMonitor/index.tsx @@ -42,8 +42,11 @@ import { type Monitor, type MonitorType, type GamesMap, + type HttpMethod, supportsGeoCheck, DefaultPageSpeedStrategy, + DefaultHttpMethod, + HttpMethods, } from "@/Types/Monitor"; import type { Notification } from "@/Types/Notification"; import type { Tag } from "@/Types/Tag"; @@ -259,7 +262,7 @@ const CreateMonitorPage = () => { resolver: zodResolver(schema), defaultValues: defaults, }); - const { control, watch, handleSubmit, clearErrors, trigger, reset } = form; + const { control, watch, handleSubmit, clearErrors, trigger, reset, setValue } = form; useEffect(() => { reset(defaults); @@ -271,6 +274,7 @@ const CreateMonitorPage = () => { const showStep = (step: number) => isEditMode || currentStep === step; const watchedType = watch("type") as MonitorType; + const watchedMethod = watch("method") as HttpMethod | undefined; const watchedUseAdvancedMatching = watch("useAdvancedMatching") as boolean; const watchGeoCheckEnabled = watch("geoCheckEnabled") as boolean; @@ -1091,6 +1095,50 @@ const CreateMonitorPage = () => { subtitle={t("pages.createMonitor.form.advanced.description")} rightContent={ + ( + + + + {t( + `pages.createMonitor.form.advanced.option.method.description.${field.value ?? DefaultHttpMethod}` + )} + + + )} + /> { ); }} /> - ( - - field.onChange(e.target.checked)} - /> - - {t( - "pages.createMonitor.form.advanced.option.advancedMatching.label" - )} - - - )} - /> - {watchedUseAdvancedMatching && ( + {watchedMethod !== "HEAD" && ( + ( + + field.onChange(e.target.checked)} + /> + + {t( + "pages.createMonitor.form.advanced.option.advancedMatching.label" + )} + + + )} + /> + )} + {watchedUseAdvancedMatching && watchedMethod !== "HEAD" && ( ), render: (row) => { - return row.type; + return row.type === "http" && row.method + ? `${row.type} (${row.method})` + : row.type; }, }, { diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 6e65aea62..2e6c7db2c 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -490,6 +490,13 @@ "advanced": { "description": "Optional settings for advanced use cases", "option": { + "method": { + "label": "Request method", + "description": { + "GET": "GET fetches the full response including the body. Advanced matching fully supported", + "HEAD": "HEAD fetches only response headers for reducing load on the target. Supports status code matching but not advanced matching as there is no body." + } + }, "advancedMatching": { "label": "Use advanced matching" },