import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, cn, } from "@methanium/ui"; import { createFileRoute, notFound } from "@tanstack/react-router"; import { Check, Loader2, Plus, ShieldAlert, Trash2 } from "lucide-react"; import { type FormEvent, useEffect, useRef, useState } from "react"; import type { Incident, Severity } from "../status"; import { formatTime } from "../utils"; export const Route = createFileRoute("/edit")({ beforeLoad: async () => { try { const response = await fetch("/api/admin", { cache: "no-store" }); if (response.status !== 204) throw notFound(); } catch { throw notFound(); } }, component: IncidentEditor, }); const severityLabels: Record = { minor: "Minor", major: "Major", critical: "Critical", }; function IncidentEditor() { const [incidents, setIncidents] = useState([]); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [deletingId, setDeletingId] = useState(null); const [error, setError] = useState(null); async function refresh() { try { const response = await fetch("/api/incidents", { cache: "no-store" }); if (!response.ok) { throw new Error(`Request failed with HTTP ${response.status}`); } setIncidents((await response.json()) as Incident[]); setError(null); } catch (cause) { setError(cause instanceof Error ? cause.message : String(cause)); } finally { setLoading(false); } } useEffect(() => { void refresh(); }, []); async function create(event: FormEvent) { event.preventDefault(); const form = event.currentTarget; const data = new FormData(form); setSubmitting(true); try { const response = await fetch("/api/incidents", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ title: data.get("title"), message: data.get("message"), severity: data.get("severity"), }), }); if (!response.ok) { const body = (await response.json()) as { error?: string }; throw new Error( body.error ?? `Request failed with HTTP ${response.status}`, ); } form.reset(); await refresh(); } catch (cause) { setError(cause instanceof Error ? cause.message : String(cause)); } finally { setSubmitting(false); } } async function resolve(id: string) { try { const response = await fetch(`/api/incidents/${id}/resolve`, { method: "POST", }); if (!response.ok) { throw new Error(`Request failed with HTTP ${response.status}`); } await refresh(); } catch (cause) { setError(cause instanceof Error ? cause.message : String(cause)); } } async function deleteIncident(id: string) { setDeletingId(id); try { const response = await fetch(`/api/incidents/${id}`, { method: "DELETE", }); if (!response.ok) { throw new Error(`Request failed with HTTP ${response.status}`); } await refresh(); } catch (cause) { setError(cause instanceof Error ? cause.message : String(cause)); } finally { setDeletingId(null); } } const active = incidents.filter((incident) => !incident.resolvedAt); const resolved = incidents .filter((incident) => incident.resolvedAt) .toReversed(); return (

Incident management

{error && (
{error}
)}

Create incident