Skip to content

Commit 42085d7

Browse files
authored
Merge pull request #1754 from YinDongFang/feature/json-validation
Implement json validation UI
2 parents c3849a7 + 133468c commit 42085d7

File tree

5 files changed

+150
-4
lines changed

5 files changed

+150
-4
lines changed

Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ export const updateUptimeMonitor = createAsyncThunk(
8888
description: monitor.description,
8989
interval: monitor.interval,
9090
notifications: monitor.notifications,
91+
matchMethod: monitor.matchMethod,
92+
expectedValue: monitor.expectedValue,
93+
jsonPath: monitor.jsonPath,
9194
};
9295
const res = await networkService.updateMonitor({
9396
authToken: authToken,

Client/src/Pages/Uptime/Configure/index.jsx

+67
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ const Configure = () => {
6161
"notify-email-default": "notification-email",
6262
};
6363

64+
const matchMethodOptions = [
65+
{ _id: "equal", name: "Equal" },
66+
{ _id: "include", name: "Include" },
67+
{ _id: "regex", name: "Regex" },
68+
];
69+
70+
const expectedValuePlaceholders = {
71+
regex: "^[\w.-][email protected]$",
72+
73+
include: "@gmail.com"
74+
};
75+
6476
useEffect(() => {
6577
const fetchMonitor = async () => {
6678
try {
@@ -439,6 +451,61 @@ const Configure = () => {
439451
onChange={(event) => handleChange(event, "interval")}
440452
items={frequencies}
441453
/>
454+
{
455+
monitor.type === "http" && <>
456+
<Select
457+
id="match-method"
458+
label="Match Method"
459+
value={monitor.matchMethod || "equal"}
460+
onChange={(event) => handleChange(event, "matchMethod")}
461+
items={matchMethodOptions}
462+
/>
463+
<Stack>
464+
<TextInput
465+
type="text"
466+
id="expected-value"
467+
label="Expected value"
468+
isOptional={true}
469+
placeholder={expectedValuePlaceholders[monitor.matchMethod || "equal"]}
470+
value={monitor.expectedValue}
471+
onChange={(event) => handleChange(event, "expectedValue")}
472+
error={errors["expectedValue"] ? true : false}
473+
helperText={errors["expectedValue"]}
474+
/>
475+
<Typography
476+
component="span"
477+
color={theme.palette.primary.contrastTextTertiary}
478+
opacity={0.8}
479+
>
480+
The expected value is used to match against response result, and the match determines the status.
481+
</Typography>
482+
</Stack>
483+
<Stack>
484+
<TextInput
485+
type="text"
486+
id="json-path"
487+
label="JSON Path"
488+
isOptional={true}
489+
placeholder="data.email"
490+
value={monitor.jsonPath}
491+
onChange={(event) => handleChange(event, "jsonPath")}
492+
error={errors["jsonPath"] ? true : false}
493+
helperText={errors["jsonPath"]}
494+
/>
495+
<Typography
496+
component="span"
497+
color={theme.palette.primary.contrastTextTertiary}
498+
opacity={0.8}
499+
>
500+
This expression will be evaluated against the reponse JSON data and the result will be used to match against the expected value. See&nbsp;
501+
<Typography component="a" href="https://jmespath.org/" target="_blank" color="info">
502+
jmespath.org
503+
</Typography>
504+
&nbsp;for query language documentation.
505+
</Typography>
506+
</Stack>
507+
</>
508+
}
442509
</Stack>
443510
</ConfigBox>
444511
<Stack

Client/src/Pages/Uptime/Create/index.jsx

+73
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ const CreateMonitor = () => {
3333
{ _id: 5, name: "5 minutes" },
3434
];
3535

36+
const matchMethodOptions = [
37+
{ _id: "equal", name: "Equal" },
38+
{ _id: "include", name: "Include" },
39+
{ _id: "regex", name: "Regex" },
40+
];
41+
42+
const expectedValuePlaceholders = {
43+
regex: "^[\w.-][email protected]$",
44+
45+
include: "@gmail.com"
46+
};
47+
3648
const monitorTypeMaps = {
3749
http: {
3850
label: "URL to monitor",
@@ -92,6 +104,12 @@ const CreateMonitor = () => {
92104
interval: monitor.interval * MS_PER_MINUTE,
93105
};
94106

107+
if (monitor.type === "http") {
108+
form.expectedValue = monitor.expectedValue;
109+
form.jsonPath = monitor.jsonPath;
110+
form.matchMethod = monitor.matchMethod;
111+
}
112+
95113
const { error } = monitorValidation.validate(form, {
96114
abortEarly: false,
97115
});
@@ -398,6 +416,61 @@ const CreateMonitor = () => {
398416
onChange={(event) => handleChange(event, "interval")}
399417
items={SELECT_VALUES}
400418
/>
419+
{
420+
monitor.type === "http" && <>
421+
<Select
422+
id="match-method"
423+
label="Match Method"
424+
value={monitor.matchMethod || "equal"}
425+
onChange={(event) => handleChange(event, "matchMethod")}
426+
items={matchMethodOptions}
427+
/>
428+
<Stack>
429+
<TextInput
430+
type="text"
431+
id="expected-value"
432+
label="Expected value"
433+
isOptional={true}
434+
placeholder={expectedValuePlaceholders[monitor.matchMethod || "equal"]}
435+
value={monitor.expectedValue}
436+
onChange={(event) => handleChange(event, "expectedValue")}
437+
error={errors["expectedValue"] ? true : false}
438+
helperText={errors["expectedValue"]}
439+
/>
440+
<Typography
441+
component="span"
442+
color={theme.palette.primary.contrastTextTertiary}
443+
opacity={0.8}
444+
>
445+
The expected value is used to match against response result, and the match determines the status.
446+
</Typography>
447+
</Stack>
448+
<Stack>
449+
<TextInput
450+
type="text"
451+
id="json-path"
452+
label="JSON Path"
453+
isOptional={true}
454+
placeholder="data.email"
455+
value={monitor.jsonPath}
456+
onChange={(event) => handleChange(event, "jsonPath")}
457+
error={errors["jsonPath"] ? true : false}
458+
helperText={errors["jsonPath"]}
459+
/>
460+
<Typography
461+
component="span"
462+
color={theme.palette.primary.contrastTextTertiary}
463+
opacity={0.8}
464+
>
465+
This expression will be evaluated against the reponse JSON data and the result will be used to match against the expected value. See&nbsp;
466+
<Typography component="a" href="https://jmespath.org/" target="_blank" color="info">
467+
jmespath.org
468+
</Typography>
469+
&nbsp;for query language documentation.
470+
</Typography>
471+
</Stack>
472+
</>
473+
}
401474
</Stack>
402475
</ConfigBox>
403476
<Stack

Client/src/Validation/validation.js

+3
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ const monitorValidation = joi.object({
161161
"number.base": "Frequency must be a number.",
162162
"any.required": "Frequency is required.",
163163
}),
164+
expectedValue: joi.string().allow(""),
165+
jsonPath: joi.string().allow(""),
166+
matchMethod: joi.string(),
164167
});
165168

166169
const imageValidation = joi.object({

Server/validation/joi.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ const createMonitorBodyValidation = joi.object({
194194
}),
195195
notifications: joi.array().items(joi.object()),
196196
secret: joi.string(),
197-
jsonPath: joi.string(),
198-
expectedValue: joi.string(),
197+
jsonPath: joi.string().allow(""),
198+
expectedValue: joi.string().allow(""),
199199
matchMethod: joi.string(),
200200
});
201201

@@ -205,8 +205,8 @@ const editMonitorBodyValidation = joi.object({
205205
interval: joi.number(),
206206
notifications: joi.array().items(joi.object()),
207207
secret: joi.string(),
208-
jsonPath: joi.string(),
209-
expectedValue: joi.string(),
208+
jsonPath: joi.string().allow(""),
209+
expectedValue: joi.string().allow(""),
210210
matchMethod: joi.string(),
211211
});
212212

0 commit comments

Comments
 (0)