import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { redirect, useNavigate, useSearchParams } from "react-router"; import { toast } from "sonner"; import { useState, useEffect } from "react"; import { cancelDoctorMutation, deleteRepositoryMutation, getRepositoryOptions, listSnapshotsOptions, startDoctorMutation, } from "~/client/api-client/@tanstack/react-query.gen"; import { Button } from "~/client/components/ui/button"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogHeader, AlertDialogTitle, } from "~/client/components/ui/alert-dialog"; import { parseError } from "~/client/lib/errors"; import { getRepository } from "~/client/api-client/sdk.gen"; import type { Route } from "./+types/repository-details"; import { cn } from "~/client/lib/utils"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs"; import { RepositoryInfoTabContent } from "../tabs/info"; import { RepositorySnapshotsTabContent } from "../tabs/snapshots"; import { Square, Stethoscope, Trash2 } from "lucide-react"; export const handle = { breadcrumb: (match: Route.MetaArgs) => [ { label: "Repositories", href: "/repositories" }, { label: match.loaderData?.name || match.params.id }, ], }; export function meta({ params, loaderData }: Route.MetaArgs) { return [ { title: `Zerobyte - ${loaderData?.name || params.id}` }, { name: "description", content: "View repository configuration, status, and snapshots.", }, ]; } export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => { const repository = await getRepository({ path: { id: params.id ?? "" } }); if (repository.data) return repository.data; return redirect("/repositories"); }; export default function RepositoryDetailsPage({ loaderData }: Route.ComponentProps) { const navigate = useNavigate(); const queryClient = useQueryClient(); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [searchParams, setSearchParams] = useSearchParams(); const activeTab = searchParams.get("tab") || "info"; const { data } = useQuery({ ...getRepositoryOptions({ path: { id: loaderData.id } }), initialData: loaderData, }); useEffect(() => { void queryClient.prefetchQuery(listSnapshotsOptions({ path: { id: data.id } })); }, [queryClient, data.id]); const deleteRepo = useMutation({ ...deleteRepositoryMutation(), onSuccess: () => { toast.success("Repository deleted successfully"); void navigate("/repositories"); }, onError: (error) => { toast.error("Failed to delete repository", { description: parseError(error)?.message, }); }, }); const startDoctor = useMutation({ ...startDoctorMutation(), onError: (error) => { toast.error("Failed to start doctor", { description: parseError(error)?.message, }); }, }); const cancelDoctor = useMutation({ ...cancelDoctorMutation(), onSuccess: () => { toast.info("Doctor operation cancelled"); }, onError: (error) => { toast.error("Failed to cancel doctor", { description: parseError(error)?.message, }); }, }); const handleConfirmDelete = () => { setShowDeleteConfirm(false); deleteRepo.mutate({ path: { id: data.id } }); }; return ( <>
{data.status || "unknown"} {data.type}
{data.status === "doctor" ? ( ) : ( )}
setSearchParams({ tab: value })}> Configuration Snapshots Delete repository? Are you sure you want to delete the repository {data.name}? This will not remove the actual data from the backend storage, only the repository configuration will be deleted.

All backup schedules associated with this repository will also be removed.
Cancel Delete repository
); }