import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; import { useNavigate, useSearch } from "@tanstack/react-router"; import { useState } from "react"; import { toast } from "sonner"; import { Activity, ChevronDown, HardDrive, HeartIcon, Pencil, Plug, Trash2, Unplug } from "lucide-react"; import { deleteVolumeMutation, getVolumeOptions, healthCheckVolumeMutation, mountVolumeMutation, unmountVolumeMutation, updateVolumeMutation, } from "~/client/api-client/@tanstack/react-query.gen"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, 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 { Switch } from "~/client/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs"; import { ManagedBadge } from "~/client/components/managed-badge"; import { parseError } from "~/client/lib/errors"; import { cn } from "~/client/lib/utils"; import { VolumeInfoTabContent } from "../tabs/info"; import { FilesTabContent } from "../tabs/files"; import { useTimeFormat } from "~/client/lib/datetime"; export function VolumeDetails({ volumeId }: { volumeId: string }) { const navigate = useNavigate(); const searchParams = useSearch({ from: "/(dashboard)/volumes/$volumeId/" }); const activeTab = searchParams.tab || "info"; const { formatDateTime, formatTimeAgo } = useTimeFormat(); const { data } = useSuspenseQuery({ ...getVolumeOptions({ path: { shortId: volumeId } }), }); const { volume, statfs } = data; const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const mountVol = useMutation({ ...mountVolumeMutation(), }); const unmountVol = useMutation({ ...unmountVolumeMutation(), }); const deleteVol = useMutation({ ...deleteVolumeMutation(), onSuccess: () => { toast.success("Volume deleted successfully"); void navigate({ to: "/volumes" }); }, onError: (error) => { toast.error("Failed to delete volume", { description: parseError(error)?.message, }); }, }); const healthcheck = useMutation({ ...healthCheckVolumeMutation(), onSuccess: (d) => { if (d.error) { toast.error("Health check failed", { description: d.error }); return; } toast.success("Health check completed", { description: "The volume is healthy." }); }, onError: (error) => { toast.error("Health check failed", { description: error.message }); }, }); const toggleAutoRemount = useMutation({ ...updateVolumeMutation(), onSuccess: (d) => { toast.success("Volume updated", { description: `Auto remount is now ${d.autoRemount ? "enabled" : "paused"}.`, }); }, onError: (error) => { toast.error("Update failed", { description: error.message }); }, }); const handleConfirmDelete = () => { setShowDeleteConfirm(false); deleteVol.mutate({ path: { shortId: volume.shortId } }); }; const isMounted = volume.status === "mounted"; const isError = volume.status === "error"; return ( <>

{volume.name}

{volume.status} {volume.type} {volume.provisioningId && }

Created {formatDateTime(volume.createdAt)}

navigate({ to: `/volumes/${volume.shortId}/edit` })}> Edit setShowDeleteConfirm(true)} disabled={deleteVol.isPending} > Delete
Health Error Healthy Unmounted
Checked {formatTimeAgo(volume.lastHealthCheck)}
Auto-remount toggleAutoRemount.mutate({ path: { shortId: volume.shortId }, body: { autoRemount: !volume.autoRemount }, }) } disabled={toggleAutoRemount.isPending} />

Last Error

{volume.lastError}

navigate({ to: ".", search: () => ({ tab: value }) })}> Configuration Files
Delete volume? Are you sure you want to delete the volume {volume.name}? This action cannot be undone.

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