Openstatus www.openstatus.dev
at main 132 lines 3.5 kB view raw
1"use client"; 2 3import { Link } from "@/components/common/link"; 4import { 5 FormCard, 6 FormCardContent, 7 FormCardDescription, 8 FormCardFooter, 9 FormCardFooterInfo, 10 FormCardHeader, 11 FormCardTitle, 12} from "@/components/forms/form-card"; 13import { Button } from "@/components/ui/button"; 14import { 15 Form, 16 FormControl, 17 FormDescription, 18 FormField, 19 FormItem, 20 FormLabel, 21 FormMessage, 22} from "@/components/ui/form"; 23import { Input } from "@/components/ui/input"; 24import { zodResolver } from "@hookform/resolvers/zod"; 25import { useTransition } from "react"; 26import { useForm } from "react-hook-form"; 27import { toast } from "sonner"; 28import { z } from "zod"; 29 30const RETRY_MIN = 1; 31const RETRY_MAX = 10; 32export const RETRY_DEFAULT = 3; 33 34const schema = z.object({ 35 retry: z.coerce 36 .number<number>() 37 .min(RETRY_MIN) 38 .max(RETRY_MAX) 39 .prefault(RETRY_DEFAULT), 40}); 41 42type FormValues = z.input<typeof schema>; 43 44export function FormRetry({ 45 defaultValues, 46 onSubmit, 47 ...props 48}: Omit<React.ComponentProps<"form">, "onSubmit"> & { 49 defaultValues?: FormValues; 50 onSubmit: (values: FormValues) => Promise<void>; 51}) { 52 const form = useForm<FormValues>({ 53 resolver: zodResolver(schema), 54 defaultValues: defaultValues ?? { 55 retry: RETRY_DEFAULT, 56 }, 57 }); 58 const [isPending, startTransition] = useTransition(); 59 60 function submitAction(values: FormValues) { 61 if (isPending) return; 62 63 startTransition(async () => { 64 try { 65 const promise = onSubmit(values); 66 toast.promise(promise, { 67 loading: "Saving...", 68 success: "Saved", 69 error: "Failed to save", 70 }); 71 await promise; 72 } catch (error) { 73 console.error(error); 74 } 75 }); 76 } 77 78 return ( 79 <Form {...form}> 80 <form onSubmit={form.handleSubmit(submitAction)} {...props}> 81 <FormCard> 82 <FormCardHeader> 83 <FormCardTitle>Retry Policy</FormCardTitle> 84 <FormCardDescription> 85 Configure the retry policy for your monitor. 86 </FormCardDescription> 87 </FormCardHeader> 88 <FormCardContent className="grid gap-4 sm:grid-cols-2"> 89 <FormField 90 control={form.control} 91 name="retry" 92 render={({ field }) => ( 93 <FormItem> 94 <FormLabel>Retry</FormLabel> 95 <FormControl> 96 <Input 97 min={RETRY_MIN} 98 max={RETRY_MAX} 99 step={1} 100 type="number" 101 {...field} 102 /> 103 </FormControl> 104 <FormMessage /> 105 <FormDescription> 106 The retry policy is exponential backoff. 107 </FormDescription> 108 </FormItem> 109 )} 110 /> 111 </FormCardContent> 112 <FormCardFooter> 113 <FormCardFooterInfo> 114 Learn more about{" "} 115 <Link 116 href="https://docs.openstatus.dev/reference/http-monitor/#retry" 117 rel="noreferrer" 118 target="_blank" 119 > 120 retries 121 </Link> 122 . 123 </FormCardFooterInfo> 124 <Button type="submit" disabled={isPending}> 125 {isPending ? "Submitting..." : "Submit"} 126 </Button> 127 </FormCardFooter> 128 </FormCard> 129 </form> 130 </Form> 131 ); 132}