diff --git a/client/src/Hooks/useMonitorForm.ts b/client/src/Hooks/useMonitorForm.ts
index 50dc7b920..153cf9f19 100644
--- a/client/src/Hooks/useMonitorForm.ts
+++ b/client/src/Hooks/useMonitorForm.ts
@@ -33,6 +33,7 @@ export const useMonitorForm = ({
type: "http",
url: data?.url || "",
ignoreTlsErrors: data?.ignoreTlsErrors || false,
+ useAdvancedMatching: data?.useAdvancedMatching || false,
matchMethod: data?.matchMethod || "",
expectedValue: data?.expectedValue || "",
jsonPath: data?.jsonPath || "",
@@ -95,6 +96,7 @@ export const useMonitorForm = ({
type: "http",
url: "",
ignoreTlsErrors: false,
+ useAdvancedMatching: false,
matchMethod: "",
expectedValue: "",
jsonPath: "",
diff --git a/client/src/Pages/CreateMonitor/index.tsx b/client/src/Pages/CreateMonitor/index.tsx
index 313b744cd..d7d9a645e 100644
--- a/client/src/Pages/CreateMonitor/index.tsx
+++ b/client/src/Pages/CreateMonitor/index.tsx
@@ -1,5 +1,5 @@
import { useMemo } from "react";
-import { useEffect, useState } from "react";
+import { useEffect } from "react";
import { useParams, useLocation, useNavigate } from "react-router";
import { useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@@ -7,9 +7,10 @@ import { useTheme } from "@mui/material";
import Stack from "@mui/material/Stack";
import RadioGroup from "@mui/material/RadioGroup";
import FormControl from "@mui/material/FormControl";
-import { useTranslation } from "react-i18next";
+import { Trans, useTranslation } from "react-i18next";
import MenuItem from "@mui/material/MenuItem";
import Typography from "@mui/material/Typography";
+import Link from "@mui/material/Link";
import Divider from "@mui/material/Divider";
import IconButton from "@mui/material/IconButton";
import FormControlLabel from "@mui/material/FormControlLabel";
@@ -163,7 +164,7 @@ const CreateMonitorPage = () => {
const watchedType = watch("type") as MonitorType;
- const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
+ const watchedUseAdvancedMatching = watch("useAdvancedMatching") as boolean;
useEffect(() => {
clearErrors();
@@ -550,16 +551,22 @@ const CreateMonitorPage = () => {
subtitle={t("pages.createMonitor.form.advanced.description")}
rightContent={
- setShowAdvancedSettings(e.target.checked)}
+ (
+ field.onChange(e.target.checked)}
+ />
+ }
+ label={t("advancedMatching")}
/>
- }
- label={t("advancedMatching")}
+ )}
/>
- {showAdvancedSettings && (
+ {watchedUseAdvancedMatching && (
{
)}
@@ -583,7 +594,9 @@ const CreateMonitorPage = () => {
{
)}
/>
+
+
+ ),
+ }}
+ />
+
)}
diff --git a/client/src/Types/Monitor.ts b/client/src/Types/Monitor.ts
index 94b3d83d7..ddf44e56f 100644
--- a/client/src/Types/Monitor.ts
+++ b/client/src/Types/Monitor.ts
@@ -35,6 +35,7 @@ export interface Monitor {
statusWindowThreshold: number;
type: MonitorType;
ignoreTlsErrors: boolean;
+ useAdvancedMatching: boolean;
jsonPath?: string;
expectedValue?: string;
matchMethod?: MonitorMatchMethod;
diff --git a/client/src/Validation/monitor.ts b/client/src/Validation/monitor.ts
index 39fccafbd..68a15fbec 100644
--- a/client/src/Validation/monitor.ts
+++ b/client/src/Validation/monitor.ts
@@ -27,6 +27,7 @@ const httpSchema = baseSchema.extend({
type: z.literal("http"),
url: urlSchema,
ignoreTlsErrors: z.boolean(),
+ useAdvancedMatching: z.boolean(),
matchMethod: z.enum(["equal", "include", "regex", ""]).optional(),
expectedValue: z.string().optional(),
jsonPath: z.string().optional(),
diff --git a/client/src/locales/en.json b/client/src/locales/en.json
index 80cb2e206..123a1f146 100644
--- a/client/src/locales/en.json
+++ b/client/src/locales/en.json
@@ -2,6 +2,8 @@
"common": {
"appName": "Checkmate",
"monitoringAgentName": "Capture",
+ "see": "See",
+ "forDocumentation": "for query language documentation.",
"breadcrumbs": {
"home": "Home",
"details": "Details"
@@ -322,7 +324,7 @@
},
"jsonPath": {
"label": "JSONPath expression",
- "description": "This expression will be evaluated against the response JSON data and the result will be used to match against the expected value."
+ "description": "This expression will be evaluated against the response JSON data and the result will be used to match against the expected value. See jmespath.org for query language documentation."
}
}
}
diff --git a/server/src/db/models/Monitor.ts b/server/src/db/models/Monitor.ts
index 24c8ef0bf..d4cc9a872 100644
--- a/server/src/db/models/Monitor.ts
+++ b/server/src/db/models/Monitor.ts
@@ -92,6 +92,10 @@ const MonitorSchema = new Schema(
type: Boolean,
default: false,
},
+ useAdvancedMatching: {
+ type: Boolean,
+ default: false,
+ },
jsonPath: {
type: String,
},
diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts
index 9cb519303..9b30e5ac2 100644
--- a/server/src/repositories/monitors/MongoMonitorsRepository.ts
+++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts
@@ -290,6 +290,7 @@ class MongoMonitorsRepository implements IMonitorsRepository {
statusWindowThreshold: doc.statusWindowThreshold,
type: doc.type,
ignoreTlsErrors: doc.ignoreTlsErrors,
+ useAdvancedMatching: doc.useAdvancedMatching ?? false,
jsonPath: doc.jsonPath ?? undefined,
expectedValue: doc.expectedValue ?? undefined,
matchMethod: doc.matchMethod ?? undefined,
@@ -374,6 +375,7 @@ class MongoMonitorsRepository implements IMonitorsRepository {
statusWindowThreshold: doc.statusWindowThreshold,
type: doc.type,
ignoreTlsErrors: doc.ignoreTlsErrors,
+ useAdvancedMatching: doc.useAdvancedMatching ?? false,
jsonPath: doc.jsonPath ?? undefined,
expectedValue: doc.expectedValue ?? undefined,
matchMethod: doc.matchMethod ?? undefined,
diff --git a/server/src/service/infrastructure/networkService.ts b/server/src/service/infrastructure/networkService.ts
index 7db8fc6e2..92d269808 100644
--- a/server/src/service/infrastructure/networkService.ts
+++ b/server/src/service/infrastructure/networkService.ts
@@ -255,7 +255,7 @@ class NetworkService implements INetworkService {
}
private async requestHttp(monitor: Monitor): Promise {
- const { url, secret, id, teamId, type, ignoreTlsErrors, jsonPath, matchMethod, expectedValue } = monitor;
+ const { url, secret, id, teamId, type, ignoreTlsErrors, useAdvancedMatching, jsonPath, matchMethod, expectedValue } = monitor;
const httpResponse = this.buildStatusResponse({
monitor,
overrides: {
@@ -305,7 +305,7 @@ class NetworkService implements INetworkService {
timings: response.timings,
});
- if (!expectedValue && !jsonPath) {
+ if (!useAdvancedMatching) {
return httpResponse;
}
diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts
index 62ced091d..fe6ac8c8a 100644
--- a/server/src/types/monitor.ts
+++ b/server/src/types/monitor.ts
@@ -26,6 +26,7 @@ export interface Monitor {
statusWindowThreshold: number;
type: MonitorType;
ignoreTlsErrors: boolean;
+ useAdvancedMatching: boolean;
jsonPath?: string;
expectedValue?: string;
matchMethod?: MonitorMatchMethod;
diff --git a/server/src/validation/joi.ts b/server/src/validation/joi.ts
index 581d2afd2..926d3b0fe 100755
--- a/server/src/validation/joi.ts
+++ b/server/src/validation/joi.ts
@@ -158,6 +158,7 @@ const createMonitorBodyValidation = joi.object({
statusWindowThreshold: joi.number().min(1).max(100).default(60),
url: joi.string().required(),
ignoreTlsErrors: joi.boolean().default(false),
+ useAdvancedMatching: joi.boolean().default(false),
port: joi.number(),
isActive: joi.boolean(),
interval: joi.number(),
@@ -193,6 +194,7 @@ const editMonitorBodyValidation = joi.object({
notifications: joi.array().items(joi.string()),
secret: joi.string(),
ignoreTlsErrors: joi.boolean(),
+ useAdvancedMatching: joi.boolean(),
jsonPath: joi.string().allow(""),
expectedValue: joi.string().allow(""),
matchMethod: joi.string().allow(null, ""),