Merge pull request #1754 from YinDongFang/feature/json-validation

Implement json validation UI
This commit is contained in:
Alexander Holliday
2025-02-15 08:48:33 -08:00
committed by GitHub
5 changed files with 150 additions and 4 deletions

View File

@@ -88,6 +88,9 @@ export const updateUptimeMonitor = createAsyncThunk(
description: monitor.description,
interval: monitor.interval,
notifications: monitor.notifications,
matchMethod: monitor.matchMethod,
expectedValue: monitor.expectedValue,
jsonPath: monitor.jsonPath,
};
const res = await networkService.updateMonitor({
authToken: authToken,

View File

@@ -61,6 +61,18 @@ const Configure = () => {
"notify-email-default": "notification-email",
};
const matchMethodOptions = [
{ _id: "equal", name: "Equal" },
{ _id: "include", name: "Include" },
{ _id: "regex", name: "Regex" },
];
const expectedValuePlaceholders = {
regex: "^[\w.-]+@gmail.com$",
equal: "janet@gmail.com",
include: "@gmail.com"
};
useEffect(() => {
const fetchMonitor = async () => {
try {
@@ -439,6 +451,61 @@ const Configure = () => {
onChange={(event) => handleChange(event, "interval")}
items={frequencies}
/>
{
monitor.type === "http" && <>
<Select
id="match-method"
label="Match Method"
value={monitor.matchMethod || "equal"}
onChange={(event) => handleChange(event, "matchMethod")}
items={matchMethodOptions}
/>
<Stack>
<TextInput
type="text"
id="expected-value"
label="Expected value"
isOptional={true}
placeholder={expectedValuePlaceholders[monitor.matchMethod || "equal"]}
value={monitor.expectedValue}
onChange={(event) => handleChange(event, "expectedValue")}
error={errors["expectedValue"] ? true : false}
helperText={errors["expectedValue"]}
/>
<Typography
component="span"
color={theme.palette.primary.contrastTextTertiary}
opacity={0.8}
>
The expected value is used to match against response result, and the match determines the status.
</Typography>
</Stack>
<Stack>
<TextInput
type="text"
id="json-path"
label="JSON Path"
isOptional={true}
placeholder="data.email"
value={monitor.jsonPath}
onChange={(event) => handleChange(event, "jsonPath")}
error={errors["jsonPath"] ? true : false}
helperText={errors["jsonPath"]}
/>
<Typography
component="span"
color={theme.palette.primary.contrastTextTertiary}
opacity={0.8}
>
This expression will be evaluated against the reponse JSON data and the result will be used to match against the expected value. See&nbsp;
<Typography component="a" href="https://jmespath.org/" target="_blank" color="info">
jmespath.org
</Typography>
&nbsp;for query language documentation.
</Typography>
</Stack>
</>
}
</Stack>
</ConfigBox>
<Stack

View File

@@ -33,6 +33,18 @@ const CreateMonitor = () => {
{ _id: 5, name: "5 minutes" },
];
const matchMethodOptions = [
{ _id: "equal", name: "Equal" },
{ _id: "include", name: "Include" },
{ _id: "regex", name: "Regex" },
];
const expectedValuePlaceholders = {
regex: "^[\w.-]+@gmail.com$",
equal: "janet@gmail.com",
include: "@gmail.com"
};
const monitorTypeMaps = {
http: {
label: "URL to monitor",
@@ -92,6 +104,12 @@ const CreateMonitor = () => {
interval: monitor.interval * MS_PER_MINUTE,
};
if (monitor.type === "http") {
form.expectedValue = monitor.expectedValue;
form.jsonPath = monitor.jsonPath;
form.matchMethod = monitor.matchMethod;
}
const { error } = monitorValidation.validate(form, {
abortEarly: false,
});
@@ -398,6 +416,61 @@ const CreateMonitor = () => {
onChange={(event) => handleChange(event, "interval")}
items={SELECT_VALUES}
/>
{
monitor.type === "http" && <>
<Select
id="match-method"
label="Match Method"
value={monitor.matchMethod || "equal"}
onChange={(event) => handleChange(event, "matchMethod")}
items={matchMethodOptions}
/>
<Stack>
<TextInput
type="text"
id="expected-value"
label="Expected value"
isOptional={true}
placeholder={expectedValuePlaceholders[monitor.matchMethod || "equal"]}
value={monitor.expectedValue}
onChange={(event) => handleChange(event, "expectedValue")}
error={errors["expectedValue"] ? true : false}
helperText={errors["expectedValue"]}
/>
<Typography
component="span"
color={theme.palette.primary.contrastTextTertiary}
opacity={0.8}
>
The expected value is used to match against response result, and the match determines the status.
</Typography>
</Stack>
<Stack>
<TextInput
type="text"
id="json-path"
label="JSON Path"
isOptional={true}
placeholder="data.email"
value={monitor.jsonPath}
onChange={(event) => handleChange(event, "jsonPath")}
error={errors["jsonPath"] ? true : false}
helperText={errors["jsonPath"]}
/>
<Typography
component="span"
color={theme.palette.primary.contrastTextTertiary}
opacity={0.8}
>
This expression will be evaluated against the reponse JSON data and the result will be used to match against the expected value. See&nbsp;
<Typography component="a" href="https://jmespath.org/" target="_blank" color="info">
jmespath.org
</Typography>
&nbsp;for query language documentation.
</Typography>
</Stack>
</>
}
</Stack>
</ConfigBox>
<Stack

View File

@@ -161,6 +161,9 @@ const monitorValidation = joi.object({
"number.base": "Frequency must be a number.",
"any.required": "Frequency is required.",
}),
expectedValue: joi.string().allow(""),
jsonPath: joi.string().allow(""),
matchMethod: joi.string(),
});
const imageValidation = joi.object({

View File

@@ -194,8 +194,8 @@ const createMonitorBodyValidation = joi.object({
}),
notifications: joi.array().items(joi.object()),
secret: joi.string(),
jsonPath: joi.string(),
expectedValue: joi.string(),
jsonPath: joi.string().allow(""),
expectedValue: joi.string().allow(""),
matchMethod: joi.string(),
});
@@ -205,8 +205,8 @@ const editMonitorBodyValidation = joi.object({
interval: joi.number(),
notifications: joi.array().items(joi.object()),
secret: joi.string(),
jsonPath: joi.string(),
expectedValue: joi.string(),
jsonPath: joi.string().allow(""),
expectedValue: joi.string().allow(""),
matchMethod: joi.string(),
});