Openstatus www.openstatus.dev
at 4c0f4c00a38753a5d0dfd7e7b7b7706dec6f1503 280 lines 8.7 kB view raw
1"use client"; 2 3import { FormCardGroup } from "@/components/forms/form-card"; 4import { useTRPC } from "@/lib/trpc/client"; 5import { deserialize } from "@openstatus/assertions"; 6import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; 7import { useParams, useRouter } from "next/navigation"; 8import { FormDangerZone } from "./form-danger-zone"; 9import { 10 FOLLOW_REDIRECTS_DEFAULT, 11 FormFollowRedirect, 12} from "./form-follow-redirect"; 13import { FormGeneral } from "./form-general"; 14import { FormNotifiers } from "./form-notifiers"; 15import { FormOtel } from "./form-otel"; 16import { FormResponseTime } from "./form-response-time"; 17import { FormRetry, RETRY_DEFAULT } from "./form-retry"; 18import { FormSchedulingRegions } from "./form-scheduling-regions"; 19import { FormStatusPages } from "./form-status-pages"; 20import { FormTags } from "./form-tags"; 21import { FormVisibility } from "./form-visibility"; 22 23export function FormMonitorUpdate() { 24 const { id } = useParams<{ id: string }>(); 25 const trpc = useTRPC(); 26 const router = useRouter(); 27 const queryClient = useQueryClient(); 28 const { data: monitor, refetch } = useQuery( 29 trpc.monitor.get.queryOptions({ id: Number.parseInt(id) }), 30 ); 31 const { data: statusPages } = useQuery(trpc.page.list.queryOptions()); 32 const { data: privateLocations } = useQuery( 33 trpc.privateLocation.list.queryOptions(), 34 ); 35 const { data: notifications } = useQuery( 36 trpc.notification.list.queryOptions(), 37 ); 38 const { data: workspace } = useQuery(trpc.workspace.get.queryOptions()); 39 const updateRetryMutation = useMutation( 40 trpc.monitor.updateRetry.mutationOptions({ 41 onSuccess: () => refetch(), 42 }), 43 ); 44 const updateOtelMutation = useMutation( 45 trpc.monitor.updateOtel.mutationOptions({ 46 onSuccess: () => refetch(), 47 }), 48 ); 49 const updatePublicMutation = useMutation( 50 trpc.monitor.updatePublic.mutationOptions({ 51 onSuccess: () => refetch(), 52 }), 53 ); 54 const updateSchedulingRegionsMutation = useMutation( 55 trpc.monitor.updateSchedulingRegions.mutationOptions({ 56 onSuccess: () => refetch(), 57 }), 58 ); 59 const updateResponseTimeMutation = useMutation( 60 trpc.monitor.updateResponseTime.mutationOptions({ 61 onSuccess: () => refetch(), 62 }), 63 ); 64 const updateTagsMutation = useMutation( 65 trpc.monitor.updateTags.mutationOptions({ 66 onSuccess: () => refetch(), 67 }), 68 ); 69 const updateFollowRedirectsMutation = useMutation( 70 trpc.monitor.updateFollowRedirects.mutationOptions({ 71 onSuccess: () => refetch(), 72 }), 73 ); 74 75 const updateGeneralMutation = useMutation( 76 trpc.monitor.updateGeneral.mutationOptions({ 77 onSuccess: () => { 78 // NOTE: invalidate the list query to update the monitor in the list (especially the name) 79 queryClient.invalidateQueries({ 80 queryKey: trpc.monitor.list.queryKey(), 81 }); 82 refetch(); 83 }, 84 onError: (err) => { 85 // TODO: open dialog 86 console.error(err); 87 }, 88 }), 89 ); 90 91 const updateStatusPagesMutation = useMutation( 92 trpc.monitor.updateStatusPages.mutationOptions({ 93 onSuccess: () => refetch(), 94 }), 95 ); 96 97 const updateNotifiersMutation = useMutation( 98 trpc.monitor.updateNotifiers.mutationOptions({ 99 onSuccess: () => refetch(), 100 }), 101 ); 102 103 const deleteMonitorMutation = useMutation( 104 trpc.monitor.delete.mutationOptions({ 105 onSuccess: () => { 106 queryClient.invalidateQueries({ 107 queryKey: trpc.monitor.list.queryKey(), 108 }); 109 router.push("/monitors"); 110 }, 111 }), 112 ); 113 114 if ( 115 !monitor || 116 !statusPages || 117 !notifications || 118 !workspace || 119 !privateLocations 120 ) 121 return null; 122 123 return ( 124 <FormCardGroup> 125 <FormGeneral 126 defaultValues={{ 127 type: monitor.jobType as "http" | "tcp", 128 url: monitor.url, 129 name: monitor.name, 130 method: monitor.method as "GET" | "POST" | "PUT" | "PATCH" | "DELETE", 131 headers: monitor.headers ?? [], 132 body: monitor.body, 133 active: monitor.active ?? true, 134 // TODO: move to server after migration 135 assertions: monitor?.assertions 136 ? deserialize(monitor?.assertions).map((a) => a.schema) 137 : [], 138 skipCheck: false, 139 saveCheck: false, 140 }} 141 onSubmit={async (values) => { 142 await updateGeneralMutation.mutateAsync({ 143 id: Number.parseInt(id), 144 name: values.name, 145 jobType: values.type, 146 url: values.url, 147 method: values.method, 148 headers: values.headers, 149 body: values.body, 150 assertions: values.assertions, 151 skipCheck: values.skipCheck, 152 saveCheck: values.saveCheck, 153 active: values.active, 154 }); 155 }} 156 /> 157 <FormResponseTime 158 defaultValues={{ 159 timeout: monitor.timeout, 160 degradedAfter: monitor.degradedAfter ?? undefined, 161 }} 162 onSubmit={async (values) => { 163 await updateResponseTimeMutation.mutateAsync({ 164 id: Number.parseInt(id), 165 timeout: values.timeout, 166 degradedAfter: values.degradedAfter ?? undefined, 167 }); 168 }} 169 /> 170 <FormTags 171 defaultValues={{ 172 tags: monitor.tags, 173 }} 174 onSubmit={async (values) => { 175 await updateTagsMutation.mutateAsync({ 176 id: Number.parseInt(id), 177 tags: values.tags.map((tag) => tag.id), 178 }); 179 }} 180 /> 181 <FormSchedulingRegions 182 privateLocations={privateLocations} 183 defaultValues={{ 184 regions: monitor.regions, 185 periodicity: monitor.periodicity, 186 privateLocations: monitor.privateLocations.map(({ id }) => id), 187 }} 188 onSubmit={async (values) => { 189 await updateSchedulingRegionsMutation.mutateAsync({ 190 id: Number.parseInt(id), 191 regions: values.regions, 192 periodicity: values.periodicity, 193 privateLocations: values.privateLocations, 194 }); 195 }} 196 /> 197 <FormStatusPages 198 statusPages={statusPages} 199 defaultValues={{ 200 statusPages: monitor.pages.map(({ id }) => id), 201 description: monitor.description, 202 externalName: monitor.externalName ?? "", 203 }} 204 onSubmit={async (values) => { 205 await updateStatusPagesMutation.mutateAsync({ 206 id: Number.parseInt(id), 207 statusPages: values.statusPages, 208 description: values.description, 209 externalName: values.externalName, 210 }); 211 }} 212 /> 213 <FormNotifiers 214 notifiers={notifications} 215 defaultValues={{ 216 notifiers: monitor.notifications.map(({ id }) => id), 217 }} 218 onSubmit={async (values) => { 219 await updateNotifiersMutation.mutateAsync({ 220 id: Number.parseInt(id), 221 notifiers: values.notifiers, 222 }); 223 }} 224 /> 225 <FormRetry 226 defaultValues={{ 227 retry: monitor.retry ?? RETRY_DEFAULT, 228 }} 229 onSubmit={async (values) => 230 await updateRetryMutation.mutateAsync({ 231 id: Number.parseInt(id), 232 retry: values.retry ?? RETRY_DEFAULT, 233 }) 234 } 235 /> 236 <FormFollowRedirect 237 defaultValues={{ 238 followRedirects: monitor.followRedirects ?? FOLLOW_REDIRECTS_DEFAULT, 239 }} 240 onSubmit={async (values) => 241 await updateFollowRedirectsMutation.mutateAsync({ 242 id: Number.parseInt(id), 243 followRedirects: values.followRedirects ?? FOLLOW_REDIRECTS_DEFAULT, 244 }) 245 } 246 /> 247 <FormOtel 248 locked={workspace.limits.otel === false} 249 defaultValues={{ 250 endpoint: monitor.otelEndpoint ?? "", 251 headers: monitor.otelHeaders ?? [], 252 }} 253 onSubmit={async (values) => { 254 await updateOtelMutation.mutateAsync({ 255 id: Number.parseInt(id), 256 otelEndpoint: values.endpoint, 257 otelHeaders: values.headers, 258 }); 259 }} 260 /> 261 <FormVisibility 262 defaultValues={{ 263 visibility: monitor.public ?? false, 264 }} 265 onSubmit={async (values) => { 266 await updatePublicMutation.mutateAsync({ 267 id: Number.parseInt(id), 268 public: values.visibility, 269 }); 270 }} 271 /> 272 <FormDangerZone 273 title={monitor.name} 274 onSubmit={async () => { 275 await deleteMonitorMutation.mutateAsync({ id: Number.parseInt(id) }); 276 }} 277 /> 278 </FormCardGroup> 279 ); 280}