import { useState } from 'react' import { useQuery, useQueryClient } from '@tanstack/react-query' import { physicalTapeAPI, vtlAPI, type PhysicalTapeLibrary, type VirtualTapeLibrary, type VirtualTape } from '@/api/tape' import { Link } from 'react-router-dom' import { formatBytes } from '@/lib/format' export default function TapeLibraries() { const [activeTab, setActiveTab] = useState<'physical' | 'vtl'>('vtl') const [selectedLibrary, setSelectedLibrary] = useState(null) const [searchQuery, setSearchQuery] = useState('') const queryClient = useQueryClient() const { data: physicalLibraries = [], isLoading: loadingPhysical } = useQuery({ queryKey: ['physical-tape-libraries'], queryFn: physicalTapeAPI.listLibraries, enabled: activeTab === 'physical', refetchInterval: 5000, }) const { data: vtlLibraries = [], isLoading: loadingVTL } = useQuery({ queryKey: ['vtl-libraries'], queryFn: vtlAPI.listLibraries, enabled: activeTab === 'vtl', refetchInterval: 5000, }) // Get tapes for selected library const { data: libraryTapes = [] } = useQuery({ queryKey: ['vtl-library-tapes', selectedLibrary], queryFn: () => vtlAPI.getLibraryTapes(selectedLibrary!), enabled: !!selectedLibrary && activeTab === 'vtl', }) // Calculate stats const totalLibraries = activeTab === 'vtl' ? vtlLibraries.length : physicalLibraries.length const onlineLibraries = activeTab === 'vtl' ? vtlLibraries.filter(l => l.is_active).length : physicalLibraries.filter(l => l.is_active).length const totalSlots = activeTab === 'vtl' ? vtlLibraries.reduce((sum, l) => sum + l.slot_count, 0) : physicalLibraries.reduce((sum, l) => sum + l.slot_count, 0) const usedSlots = libraryTapes.filter(t => t.slot_number > 0).length // Filter libraries by search const filteredLibraries = (activeTab === 'vtl' ? vtlLibraries : physicalLibraries).filter(lib => lib.name.toLowerCase().includes(searchQuery.toLowerCase()) || (activeTab === 'vtl' && 'mhvtl_library_id' in lib && lib.mhvtl_library_id.toString().includes(searchQuery)) ) const handleRefresh = () => { queryClient.invalidateQueries({ queryKey: activeTab === 'vtl' ? ['vtl-libraries'] : ['physical-tape-libraries'] }) } return (
{/* Top Header & Breadcrumbs */}
{/* Breadcrumbs */}
Home / Virtual Tape Libraries
{/* Page Heading & Actions */}

Virtual Tape Libraries

Manage virtual tape devices, emulation profiles, and storage targets.

{activeTab === 'vtl' && ( add Create VTL )}
{/* Scrollable Content */}
{/* Tabs */}
{/* Stats Grid */}
{/* Stat Card 1 */}
dns

Total Libraries

{totalLibraries}

check_circle {onlineLibraries === totalLibraries ? 'All Online' : `${onlineLibraries} Online`}
{/* Stat Card 2 */}
database

Total Capacity

{formatBytes( activeTab === 'vtl' ? vtlLibraries.reduce((sum, l) => sum + (l.slot_count * 15 * 1024 * 1024 * 1024 * 1024), 0) : 0, 1 )}

{/* Stat Card 3 */}
album

Tapes Online

{usedSlots}

/ {totalSlots} Slots
{/* Stat Card 4 */}
swap_horiz

Active Sessions

{activeTab === 'vtl' ? vtlLibraries.reduce((sum, l) => sum + l.drive_count, 0) : physicalLibraries.reduce((sum, l) => sum + l.drive_count, 0)}

Drives
{/* Usage Progress Section */}
pie_chart

VTL Partition Usage (ZFS Pool)

{formatBytes(usedSlots * 15 * 1024 * 1024 * 1024 * 1024, 1)} /{' '} {formatBytes(totalSlots * 15 * 1024 * 1024 * 1024 * 1024, 1)} Used

0 ? (usedSlots / totalSlots) * 100 : 0}%` }} >
Compression Ratio: 1.5x Pool Healthy
{/* Main Data Table Section */}
{/* Toolbar */}
search setSearchQuery(e.target.value)} />
{/* Table */} {loadingVTL || loadingPhysical ? (

Loading libraries...

) : filteredLibraries.length === 0 ? (
database

No {activeTab === 'vtl' ? 'Virtual' : 'Physical'} Tape Libraries

{activeTab === 'vtl' ? 'Create your first virtual tape library to get started' : 'Discover physical tape libraries connected to the system'}

{activeTab === 'vtl' && ( add Create VTL Library )}
) : ( <>
{filteredLibraries.map((library) => { const isVTL = activeTab === 'vtl' const libraryId = isVTL ? (library as VirtualTapeLibrary).mhvtl_library_id : library.id const status = library.is_active ? 'Ready' : 'Offline' const statusColor = library.is_active ? 'green' : 'gray' const tapesCount = isVTL && selectedLibrary === library.id ? libraryTapes.length : 0 return ( isVTL && setSelectedLibrary(selectedLibrary === library.id ? null : library.id)} > ) })}
Library Name Status Emulation Tapes / Slots iSCSI Target Actions
e.stopPropagation()} />
shelves

{library.name}

ID: {libraryId}

{statusColor === 'green' && ( )} {statusColor === 'gray' && } {status}

{isVTL ? (library as VirtualTapeLibrary).vendor || 'MHVTL' : 'physical' in library ? (library as PhysicalTapeLibrary).vendor : 'N/A'}

LTO-8 • {library.drive_count} {library.drive_count === 1 ? 'Drive' : 'Drives'}

album {tapesCount || 0} / {library.slot_count}
0 ? ((tapesCount || 0) / library.slot_count) * 100 : 0}%`, }} >
iqn.2023-10.com.vtl:{library.name.toLowerCase().replace(/\s+/g, '')} content_copy
e.stopPropagation()} > cable
{/* Pagination */}

Showing 1-{filteredLibraries.length} of{' '} {filteredLibraries.length} libraries

)}
{/* Tape Detail Drawer */} {selectedLibrary && activeTab === 'vtl' && (
cable

Tape Management: {vtlLibraries.find((l) => l.id === selectedLibrary)?.name}

Manage virtual cartridges, import/export slots, and barcodes.

add Add Tapes
{libraryTapes.length === 0 ? (
album

No Tapes Found

This library has no tapes yet. Create tapes to get started.

add Add Tapes
) : (
{libraryTapes.map((tape) => (
album SLOT {tape.slot_number}

{tape.barcode}

{formatBytes(tape.size_bytes, 1)} / {formatBytes(tape.size_bytes, 1)}

))}
)}
)}
) }