/**
* TableSelector - Header component for switching between sand tables
*
* Displays the current table and provides a dropdown to switch between
* discovered tables or add new ones manually.
*/
import { useState } from 'react'
import { useTable, type Table } from '@/contexts/TableContext'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Badge } from '@/components/ui/badge'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover'
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from '@/components/ui/dialog'
import { toast } from 'sonner'
import {
Layers,
Plus,
Check,
Wifi,
WifiOff,
Pencil,
Trash2,
} from 'lucide-react'
export function TableSelector() {
const {
tables,
activeTable,
setActiveTable,
addTable,
removeTable,
updateTableName,
} = useTable()
const [isOpen, setIsOpen] = useState(false)
const [showAddDialog, setShowAddDialog] = useState(false)
const [showRenameDialog, setShowRenameDialog] = useState(false)
const [newTableUrl, setNewTableUrl] = useState('')
const [newTableName, setNewTableName] = useState('')
const [renameTable, setRenameTable] = useState
(null)
const [renameValue, setRenameValue] = useState('')
const [isAdding, setIsAdding] = useState(false)
const handleSelectTable = (table: Table) => {
if (table.id !== activeTable?.id) {
setActiveTable(table)
toast.success(`Switched to ${table.name}`)
}
setIsOpen(false)
}
const handleAddTable = async () => {
if (!newTableUrl.trim()) {
toast.error('Please enter a URL')
return
}
setIsAdding(true)
try {
// Ensure URL has protocol
let url = newTableUrl.trim()
if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = `http://${url}`
}
const table = await addTable(url, newTableName.trim() || undefined)
if (table) {
toast.success(`Added ${table.name}`)
setShowAddDialog(false)
setNewTableUrl('')
setNewTableName('')
} else {
toast.error('Failed to add table. Check the URL and try again.')
}
} finally {
setIsAdding(false)
}
}
const handleRename = async () => {
if (!renameTable || !renameValue.trim()) return
await updateTableName(renameTable.id, renameValue.trim())
toast.success('Table renamed')
setShowRenameDialog(false)
setRenameTable(null)
setRenameValue('')
}
const handleRemove = (table: Table) => {
if (table.isCurrent) {
toast.error("Can't remove the current table")
return
}
removeTable(table.id)
toast.success(`Removed ${table.name}`)
}
const openRenameDialog = (table: Table) => {
setRenameTable(table)
setRenameValue(table.name)
setShowRenameDialog(true)
}
// Always show if there are tables or discovering
// This allows users to manually add tables even with just one
return (
<>
{/* Header */}
Sand Tables
{/* Table list */}
{tables.map(table => (
handleSelectTable(table)}
>
{/* Status indicator */}
{table.isOnline ? (
) : (
)}
{/* Name and info */}
{table.name}
{table.isCurrent && (
This
)}
{table.host || new URL(table.url).hostname}
{/* Actions - always visible on mobile, hover on desktop */}
{!table.isCurrent && (
)}
{/* Selected indicator - far right */}
{activeTable?.id === table.id && (
)}
))}
{/* Add table button */}
{/* Add Table Dialog */}
{/* Rename Dialog */}
>
)
}