Openstatus
www.openstatus.dev
1"use client";
2
3import {
4 FormControl,
5 FormDescription,
6 FormField,
7 FormItem,
8 FormLabel,
9 FormMessage,
10} from "@/components/ui/form";
11
12import {
13 FormCard,
14 FormCardContent,
15 FormCardDescription,
16 FormCardFooter,
17 FormCardHeader,
18 FormCardTitle,
19} from "@/components/forms/form-card";
20import { Button } from "@/components/ui/button";
21import { Form } from "@/components/ui/form";
22import { Input } from "@/components/ui/input";
23import { zodResolver } from "@hookform/resolvers/zod";
24import { useTransition } from "react";
25import { useForm } from "react-hook-form";
26import { toast } from "sonner";
27import { z } from "zod";
28
29const DEGRADED = 30_000;
30const TIMEOUT = 45_000;
31
32const schema = z.object({
33 degradedAfter: z.coerce.number<number>().optional(),
34 timeout: z.coerce.number<number>(),
35});
36
37type FormValues = z.input<typeof schema>;
38
39export function FormResponseTime({
40 defaultValues,
41 onSubmit,
42 ...props
43}: Omit<React.ComponentProps<"form">, "onSubmit"> & {
44 defaultValues?: FormValues;
45 onSubmit: (values: FormValues) => Promise<void>;
46}) {
47 const form = useForm<FormValues>({
48 resolver: zodResolver(schema),
49 defaultValues: defaultValues ?? {
50 degradedAfter: DEGRADED,
51 timeout: TIMEOUT,
52 },
53 });
54 const [isPending, startTransition] = useTransition();
55
56 function submitAction(values: FormValues) {
57 if (isPending) return;
58
59 startTransition(async () => {
60 try {
61 const promise = onSubmit(values);
62 toast.promise(promise, {
63 loading: "Saving...",
64 success: () => "Saved",
65 error: "Failed to save",
66 });
67 await promise;
68 } catch (error) {
69 console.error(error);
70 }
71 });
72 }
73
74 return (
75 <Form {...form}>
76 <form onSubmit={form.handleSubmit(submitAction)} {...props}>
77 <FormCard>
78 <FormCardHeader>
79 <FormCardTitle>Response Time Thresholds</FormCardTitle>
80 <FormCardDescription>
81 Configure your degraded and timeout thresholds.
82 </FormCardDescription>
83 </FormCardHeader>
84 <FormCardContent className="grid gap-4 sm:grid-cols-2">
85 <FormField
86 control={form.control}
87 name="degradedAfter"
88 render={({ field }) => (
89 <FormItem className="self-start">
90 <FormLabel>Degraded (in ms.)</FormLabel>
91 <FormControl>
92 <Input placeholder="30000" type="number" {...field} />
93 </FormControl>
94 <FormDescription>
95 Time after which the endpoint is considered degraded.
96 </FormDescription>
97 <FormMessage />
98 </FormItem>
99 )}
100 />
101 <FormField
102 control={form.control}
103 name="timeout"
104 render={({ field }) => (
105 <FormItem className="self-start">
106 <FormLabel>Timeout (in ms.)</FormLabel>
107 <FormControl>
108 <Input placeholder="45000" type="number" {...field} />
109 </FormControl>
110 <FormDescription>
111 Max. time allowed for request to complete.
112 </FormDescription>
113 <FormMessage />
114 </FormItem>
115 )}
116 />
117 </FormCardContent>
118 <FormCardFooter>
119 <Button type="submit" disabled={isPending}>
120 {isPending ? "Submitting..." : "Submit"}
121 </Button>
122 </FormCardFooter>
123 </FormCard>
124 </form>
125 </Form>
126 );
127}