import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; import { useState } from "react"; import { useNavigate, useSearch } from "@tanstack/react-router"; import { toast } from "sonner"; import { ChevronDown, Database, Pencil, Square, Stethoscope, Trash2, Unlock } from "lucide-react"; import { cancelDoctorMutation, deleteRepositoryMutation, getRepositoryOptions, startDoctorMutation, unlockRepositoryMutation, } from "~/client/api-client/@tanstack/react-query.gen"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogHeader, AlertDialogTitle, } from "~/client/components/ui/alert-dialog"; import { Badge } from "~/client/components/ui/badge"; import { Button } from "~/client/components/ui/button"; import { Card } from "~/client/components/ui/card"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "~/client/components/ui/dropdown-menu"; import { Separator } from "~/client/components/ui/separator"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs"; import { parseError } from "~/client/lib/errors"; import { cn } from "~/client/lib/utils"; import type { BackupSchedule, Snapshot } from "~/client/lib/types"; import type { GetRepositoryStatsResponse } from "~/client/api-client/types.gen"; import { RepositoryInfoTabContent } from "../tabs/info"; import { RepositorySnapshotsTabContent } from "../tabs/snapshots"; import { useTimeFormat } from "~/client/lib/datetime"; export default function RepositoryDetailsPage({ repositoryId, initialSnapshots, initialBackupSchedules, initialStats, }: { repositoryId: string; initialSnapshots?: Snapshot[]; initialBackupSchedules?: BackupSchedule[]; initialStats?: GetRepositoryStatsResponse; }) { const { formatDateTime, formatTimeAgo } = useTimeFormat(); const navigate = useNavigate(); const { tab } = useSearch({ from: "/(dashboard)/repositories/$repositoryId/" }); const activeTab = tab || "info"; const { data: repository } = useSuspenseQuery({ ...getRepositoryOptions({ path: { shortId: repositoryId } }), }); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const deleteRepo = useMutation({ ...deleteRepositoryMutation(), onSuccess: () => { toast.success("Repository deleted successfully"); void navigate({ to: "/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 unlockRepo = useMutation({ ...unlockRepositoryMutation(), }); const handleConfirmDelete = () => { setShowDeleteConfirm(false); deleteRepo.mutate({ path: { shortId: repository.shortId } }); }; const isDoctorRunning = repository.status === "doctor"; return ( <>
Created {formatDateTime(repository.createdAt)} · Last checked {formatTimeAgo(repository.lastChecked)}
Last Error
{repository.lastError}