Openstatus www.openstatus.dev

๐Ÿš€ text body assertions (#895)

authored by

Thibault Le Ouay and committed by
GitHub
fe20e7c3 1b3ae1b3

+85 -15
+74 -2
apps/web/src/components/forms/monitor/section-assertions.tsx
··· 7 7 import { 8 8 numberCompareDictionary, 9 9 stringCompareDictionary, 10 + textBodyAssertion, 10 11 } from "@openstatus/assertions"; 11 12 import type { InsertMonitor } from "@openstatus/db/src/schema"; 12 13 import { ··· 45 46 control: form.control, 46 47 name: "headerAssertions", 47 48 }); 49 + const textBodyAssertions = useFieldArray({ 50 + control: form.control, 51 + name: "textBodyAssertions", 52 + }); 53 + 48 54 return ( 49 55 <div className="grid w-full gap-4"> 50 56 <SectionHeader ··· 90 96 <SelectItem key={key} value={key}> 91 97 {value} 92 98 </SelectItem> 93 - ), 99 + ) 94 100 )} 95 101 </SelectContent> 96 102 </Select> ··· 151 157 <SelectItem key={key} value={key}> 152 158 {value} 153 159 </SelectItem> 154 - ), 160 + ) 155 161 )} 156 162 </SelectContent> 157 163 </Select> ··· 174 180 </div> 175 181 </div> 176 182 ))} 183 + {textBodyAssertions.fields.map((f, i) => ( 184 + <div key={f.id} className="grid grid-cols-12 items-center gap-4"> 185 + <p className="col-span-2 text-muted-foreground text-sm">Body</p> 186 + <div className="col-span-3" /> 187 + <FormField 188 + control={form.control} 189 + name={`statusAssertions.${i}.compare`} 190 + render={({ field }) => ( 191 + <FormItem className="col-span-3 w-full"> 192 + <Select 193 + onValueChange={field.onChange} 194 + defaultValue={field.value} 195 + > 196 + <FormControl> 197 + <SelectTrigger> 198 + <SelectValue defaultValue="eq" placeholder="Equal" /> 199 + </SelectTrigger> 200 + </FormControl> 201 + <SelectContent> 202 + {Object.entries(stringCompareDictionary).map( 203 + ([key, value]) => ( 204 + <SelectItem key={key} value={key}> 205 + {value} 206 + </SelectItem> 207 + ) 208 + )} 209 + </SelectContent> 210 + </Select> 211 + </FormItem> 212 + )} 213 + /> 214 + <Input 215 + {...form.register(`textBodyAssertions.${i}.target`, { 216 + required: true, 217 + })} 218 + type="number" 219 + placeholder="<html>...</html>" 220 + className="col-span-3" 221 + /> 222 + <div className="col-span-1"> 223 + <Button 224 + size="icon" 225 + onClick={() => textBodyAssertions.remove(i)} 226 + variant="ghost" 227 + type="button" 228 + > 229 + <Icons.trash className="h-4 w-4" /> 230 + </Button> 231 + </div> 232 + </div> 233 + ))} 177 234 <div className="flex gap-4"> 178 235 <Button 179 236 variant="outline" ··· 203 260 } 204 261 > 205 262 Add Header Assertion 263 + </Button> 264 + 265 + <Button 266 + variant="outline" 267 + type="button" 268 + onClick={() => 269 + textBodyAssertions.append({ 270 + version: "v1", 271 + type: "textBody", 272 + compare: "eq", 273 + target: "", 274 + }) 275 + } 276 + > 277 + Add String Body Assertion 206 278 </Button> 207 279 </div> 208 280 </div>
+11 -13
packages/db/src/schema/monitors/validation.ts
··· 35 35 return String(val); 36 36 }, z.string()); 37 37 38 - const headersToArraySchema = z.preprocess( 39 - (val) => { 40 - // early return in case the header is already an array 41 - if (Array.isArray(val)) { 42 - return val; 43 - } 44 - if (String(val).length > 0) { 45 - return JSON.parse(String(val)); 46 - } 47 - return []; 48 - }, 49 - z.array(z.object({ key: z.string(), value: z.string() })).default([]), 50 - ); 38 + const headersToArraySchema = z.preprocess((val) => { 39 + // early return in case the header is already an array 40 + if (Array.isArray(val)) { 41 + return val; 42 + } 43 + if (String(val).length > 0) { 44 + return JSON.parse(String(val)); 45 + } 46 + return []; 47 + }, z.array(z.object({ key: z.string(), value: z.string() })).default([])); 51 48 52 49 export const selectMonitorSchema = createSelectSchema(monitor, { 53 50 periodicity: monitorPeriodicitySchema.default("10m"), ··· 78 75 tags: z.array(z.number()).optional().default([]), 79 76 statusAssertions: z.array(assertions.statusAssertion).optional(), 80 77 headerAssertions: z.array(assertions.headerAssertion).optional(), 78 + textBodyAssertions: z.array(assertions.textBodyAssertion).optional(), 81 79 }); 82 80 83 81 export const selectMonitorToPageSchema = createSelectSchema(monitorsToPages);