import { useQuery } from "@tanstack/react-query"; import { intervalToDuration } from "date-fns"; import { Calendar, Clock, Database, FolderTree, HardDrive } from "lucide-react"; import { useState } from "react"; import { listSnapshotsOptions } from "~/api-client/@tanstack/react-query.gen"; import type { ListSnapshotsResponse } from "~/api-client/types.gen"; import { ByteSize } from "~/components/bytes-size"; import { Button } from "~/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card"; import { Input } from "~/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/components/ui/table"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/components/ui/tooltip"; import type { Repository } from "~/lib/types"; type Props = { repository: Repository; }; type Snapshot = ListSnapshotsResponse["snapshots"][0]; export const RepositorySnapshotsTabContent = ({ repository }: Props) => { const [searchQuery, setSearchQuery] = useState(""); const { data, isLoading, error } = useQuery({ ...listSnapshotsOptions({ path: { name: repository.name } }), refetchInterval: 10000, refetchOnWindowFocus: true, }); const snapshots = data?.snapshots || []; const filteredSnapshots = snapshots.filter((snapshot: Snapshot) => { if (!searchQuery) return true; const searchLower = searchQuery.toLowerCase(); return ( snapshot.short_id.toLowerCase().includes(searchLower) || snapshot.paths.some((path) => path.toLowerCase().includes(searchLower)) ); }); const hasNoSnapshots = snapshots.length === 0; const hasNoFilteredSnapshots = filteredSnapshots.length === 0 && !hasNoSnapshots; const formatSnapshotDuration = (seconds: number) => { const duration = intervalToDuration({ start: 0, end: seconds * 1000 }); const parts: string[] = []; if (duration.days) parts.push(`${duration.days}d`); if (duration.hours) parts.push(`${duration.hours}h`); if (duration.minutes) parts.push(`${duration.minutes}m`); if (duration.seconds || parts.length === 0) parts.push(`${duration.seconds || 0}s`); return parts.join(" "); }; if (repository.status === "error") { return (

Repository Error

This repository is in an error state and cannot be accessed.

{repository.lastError && (

{repository.lastError}

)}
); } if (isLoading && !data) { return (

Loading snapshots...

); } if (error) { return (

Failed to Load Snapshots

{error.message}

); } if (hasNoSnapshots) { return (

No snapshots yet

Snapshots are point-in-time backups of your data. Create your first backup to see it here.

); } return (
Snapshots Backup snapshots stored in this repository. Total: {snapshots.length}
setSearchQuery(e.target.value)} />
Snapshot ID Date & Time Size Duration Paths {hasNoFilteredSnapshots ? (

No snapshots match your search.

) : ( filteredSnapshots.map((snapshot) => (
{snapshot.short_id}
{new Date(snapshot.time).toLocaleString()}
{formatSnapshotDuration(snapshot.duration / 1000)}
{snapshot.paths[0].split("/").filter(Boolean).pop() || "/"} +{snapshot.paths.length - 1}
{snapshot.paths.slice(1).map((path) => (
{path}
))}
)) )}
{hasNoFilteredSnapshots ? "No snapshots match filters." : `Showing ${filteredSnapshots.length} of ${snapshots.length}`} {!hasNoFilteredSnapshots && ( Total size:  sum + s.size, 0)} base={1024} maximumFractionDigits={1} /> )}
); };