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 { deleteRepositoryMutation, doctorRepositoryMutation, getRepositoryOptions, listSnapshotsOptions, } 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 { Loader2, Stethoscope, Trash2, X } from "lucide-react"; export const handle = { breadcrumb: (match: Route.MetaArgs) => [ { label: "Repositories", href: "/repositories" }, { label: match.params.name }, ], }; export function meta({ params }: Route.MetaArgs) { return [ { title: `Zerobyte - ${params.name}` }, { name: "description", content: "View repository configuration, status, and snapshots.", }, ]; } export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => { const repository = await getRepository({ path: { name: params.name ?? "" } }); if (repository.data) return repository.data; return redirect("/repositories"); }; export default function RepositoryDetailsPage({ loaderData }: Route.ComponentProps) { const [showDoctorResults, setShowDoctorResults] = useState(false); 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: { name: loaderData.name } }), initialData: loaderData, }); useEffect(() => { queryClient.prefetchQuery(listSnapshotsOptions({ path: { name: data.name } })); }, [queryClient, data.name]); const deleteRepo = useMutation({ ...deleteRepositoryMutation(), onSuccess: () => { toast.success("Repository deleted successfully"); navigate("/repositories"); }, onError: (error) => { toast.error("Failed to delete repository", { description: parseError(error)?.message, }); }, }); const doctorMutation = useMutation({ ...doctorRepositoryMutation(), onSuccess: (data) => { if (data) { setShowDoctorResults(true); if (data.success) { toast.success("Repository doctor completed successfully"); } else { toast.warning("Doctor completed with some issues", { description: "Check the details for more information", richColors: true, }); } } }, onError: (error) => { toast.error("Failed to run doctor", { description: parseError(error)?.message, }); }, }); const handleConfirmDelete = () => { setShowDeleteConfirm(false); deleteRepo.mutate({ path: { name: data.name } }); }; const getStepLabel = (step: string) => { switch (step) { case "unlock": return "Unlock Repository"; case "check": return "Check Repository"; case "repair_index": return "Repair Index"; case "recheck": return "Re-check Repository"; default: return step; } }; return ( <>
{data.status || "unknown"} {data.type}
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.
Cancel Delete repository
Doctor results Repository doctor operation completed {doctorMutation.data && (
{doctorMutation.data.steps.map((step) => (
{getStepLabel(step.step)} {step.success ? "Success" : "Warning"}
{step.error &&

{step.error}

}
))}
)}
); }