import { useSuspenseQuery } from "@tanstack/react-query"; import { ArrowDown, ArrowUp, ArrowUpDown, Database, Plus, RotateCcw } from "lucide-react"; import { useState } from "react"; import { listRepositoriesOptions } from "~/client/api-client/@tanstack/react-query.gen"; import { RepositoryIcon } from "~/client/components/repository-icon"; import { Button } from "~/client/components/ui/button"; import { Card } from "~/client/components/ui/card"; import { Input } from "~/client/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table"; import { cn } from "~/client/lib/utils"; import { StatusDot } from "~/client/components/status-dot"; import { EmptyState } from "~/client/components/empty-state"; import { useNavigate } from "@tanstack/react-router"; import type { RepositoryBackend } from "@zerobyte/core/restic"; type SortColumn = "name" | "backend" | "status" | "compression"; type SortDirection = "asc" | "desc"; type RepositoryRow = { id: string; shortId: string; name: string; type: RepositoryBackend; status: string | null; compressionMode?: string | null; }; const getSortValue = (column: SortColumn, repository: RepositoryRow) => { switch (column) { case "name": return repository.name; case "backend": return repository.type; case "status": return repository.status || ""; case "compression": return repository.compressionMode || ""; } }; export function RepositoriesPage() { const [searchQuery, setSearchQuery] = useState(""); const [statusFilter, setStatusFilter] = useState(""); const [backendFilter, setBackendFilter] = useState(""); const [sortColumn, setSortColumn] = useState("name"); const [sortDirection, setSortDirection] = useState("asc"); const clearFilters = () => { setSearchQuery(""); setStatusFilter(""); setBackendFilter(""); }; const navigate = useNavigate(); const { data } = useSuspenseQuery({ ...listRepositoriesOptions(), }); const repositories = data as RepositoryRow[]; const toggleSort = (column: SortColumn) => { if (sortColumn === column) { setSortDirection((prev) => (prev === "asc" ? "desc" : "asc")); return; } setSortColumn(column); setSortDirection("asc"); }; const renderSortIcon = (column: SortColumn) => { if (sortColumn !== column) { return ; } return sortDirection === "asc" ? ( ) : ( ); }; const filteredRepositories = repositories.filter((repository) => { const matchesSearch = repository.name.toLowerCase().includes(searchQuery.toLowerCase()); const matchesStatus = !statusFilter || repository.status === statusFilter; const matchesBackend = !backendFilter || repository.type === backendFilter; return matchesSearch && matchesStatus && matchesBackend; }); const sortedFilteredRepositories = [...filteredRepositories].sort((a, b) => { const valueA = getSortValue(sortColumn, a).toLowerCase(); const valueB = getSortValue(sortColumn, b).toLowerCase(); const result = valueA.localeCompare(valueB); return sortDirection === "asc" ? result : -result; }); const hasNoRepositories = repositories.length === 0; const hasNoFilteredRepositories = sortedFilteredRepositories.length === 0 && !hasNoRepositories; if (hasNoRepositories) { return ( navigate({ to: "/repositories/create" })}> Create repository } /> ); } return (
setSearchQuery(e.target.value)} /> {(searchQuery || statusFilter || backendFilter) && ( )}

No repositories match your filters.

{sortedFilteredRepositories.map((repository) => ( navigate({ to: `/repositories/${repository.shortId}` })} >
{repository.name}
{repository.type} {repository.compressionMode || "off"}
))}
{hasNoFilteredRepositories ? ( "No repositories match filters." ) : ( {sortedFilteredRepositories.length} repositor {sortedFilteredRepositories.length === 1 ? "y" : "ies"} )}
); }