import { useMutation, useQuery } from "@tanstack/react-query"; import { useNavigate, useParams, useSearchParams } from "react-router"; import { toast } from "sonner"; import { useState } from "react"; import { Plug, Unplug } from "lucide-react"; import { StatusDot } from "~/client/components/status-dot"; import { Button } from "~/client/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogHeader, AlertDialogTitle, } from "~/client/components/ui/alert-dialog"; import { VolumeIcon } from "~/client/components/volume-icon"; import { parseError } from "~/client/lib/errors"; import { cn } from "~/client/lib/utils"; import type { Route } from "./+types/volume-details"; import { VolumeInfoTabContent } from "../tabs/info"; import { FilesTabContent } from "../tabs/files"; import { DockerTabContent } from "../tabs/docker"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip"; import { useSystemInfo } from "~/client/hooks/use-system-info"; import { getVolume } from "~/client/api-client"; import type { VolumeStatus } from "~/client/lib/types"; import { deleteVolumeMutation, getVolumeOptions, mountVolumeMutation, unmountVolumeMutation, } from "~/client/api-client/@tanstack/react-query.gen"; const getVolumeStatusVariant = (status: VolumeStatus): "success" | "neutral" | "error" | "warning" => { const statusMap = { mounted: "success" as const, unmounted: "neutral" as const, error: "error" as const, unknown: "warning" as const, }; return statusMap[status]; }; export const handle = { breadcrumb: (match: Route.MetaArgs) => [{ label: "Volumes", href: "/volumes" }, { label: match.params.name }], }; export function meta({ params }: Route.MetaArgs) { return [ { title: `Zerobyte - ${params.name}` }, { name: "description", content: "View and manage volume details, configuration, and files.", }, ]; } export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => { const volume = await getVolume({ path: { name: params.name } }); if (volume.data) return volume.data; }; export default function VolumeDetails({ loaderData }: Route.ComponentProps) { const { name } = useParams<{ name: string }>(); const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); const activeTab = searchParams.get("tab") || "info"; const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const { data } = useQuery({ ...getVolumeOptions({ path: { name: name ?? "" } }), initialData: loaderData, }); const { capabilities } = useSystemInfo(); const deleteVol = useMutation({ ...deleteVolumeMutation(), onSuccess: () => { toast.success("Volume deleted successfully"); navigate("/volumes"); }, onError: (error) => { toast.error("Failed to delete volume", { description: parseError(error)?.message, }); }, }); const mountVol = useMutation({ ...mountVolumeMutation(), onSuccess: () => { toast.success("Volume mounted successfully"); }, onError: (error) => { toast.error("Failed to mount volume", { description: parseError(error)?.message, }); }, }); const unmountVol = useMutation({ ...unmountVolumeMutation(), onSuccess: () => { toast.success("Volume unmounted successfully"); }, onError: (error) => { toast.error("Failed to unmount volume", { description: parseError(error)?.message, }); }, }); const handleConfirmDelete = () => { setShowDeleteConfirm(false); deleteVol.mutate({ path: { name: name ?? "" } }); }; if (!name) { return
Enable Docker support to access this tab.