import { FC, useState, useEffect } from 'react' import { useRouter } from 'next/router' import Link from 'next/link' import { Button, Divider, Dropdown, Typography, Listbox, Menu, Input, IconCopy, IconChevronDown, IconEdit, IconTrash, IconSearch, IconPlus, IconDatabase, IconX, IconLoader, IconRefreshCw, } from '@supabase/ui' import { PostgresSchema, PostgresTable } from '@supabase/postgres-meta' import Base64 from 'lib/base64' import { useStore } from 'hooks' import { SchemaView } from './TableEditorLayout.types' interface Props { selectedSchema?: string onSelectSchema: (schema: string) => void onAddTable: () => void onEditTable: (table: PostgresTable) => void onDeleteTable: (table: PostgresTable) => void onDuplicateTable: (table: PostgresTable) => void } const TableEditorMenu: FC = ({ selectedSchema, onSelectSchema = () => {}, onAddTable = () => {}, onEditTable = () => {}, onDeleteTable = () => {}, onDuplicateTable = () => {}, }) => { const { meta, ui } = useStore() const router = useRouter() const { id } = router.query const projectRef = ui.selectedProject?.ref const [searchText, setSearchText] = useState('') const [schemaViews, setSchemaViews] = useState([]) const [isRefreshing, setIsRefreshing] = useState(false) // We may need to shift this to the schema store and do something like meta.schema.loadViews() // I don't need we need a separate store for views useEffect(() => { let cancel = false const fetchViews = async (selectedSchema: string) => { const views: SchemaView[] = await meta.schemas.getViews(selectedSchema) if (!cancel) setSchemaViews(views) } if (selectedSchema) { fetchViews(selectedSchema) } return () => { cancel = true } }, [selectedSchema]) const refreshTables = async () => { setIsRefreshing(true) await meta.tables.load() setIsRefreshing(false) } const schemas: PostgresSchema[] = meta.schemas.list() const tables: PostgresTable[] = meta.tables.list( (table: PostgresTable) => table.schema === selectedSchema ) const schemaTables = searchText.length === 0 ? tables : tables.filter((table) => table.name.toLowerCase().includes(searchText.toLowerCase())) const filteredSchemaViews = searchText.length === 0 ? schemaViews : schemaViews.filter((view) => view.name.includes(searchText)) // Temp fix - Ideally we'd just take up all the remaining space but // can't seem to figure that out immediately const maxScrollHeight = schemaViews.length > 0 ? 270 : 515 return (
{/* Schema selection dropdown */}
{!meta.schemas.isInitialized ? (
Loading schemas...
) : ( } size="tiny" value={selectedSchema} onChange={(name: string) => { setSearchText('') setSchemaViews([]) onSelectSchema(name) }} > {schemas.map((schema) => ( {schema.name} ))} )}
{/* Add new table button */} {selectedSchema === 'public' && ( )} {/* Table search input */} } className="sbui-input-no-border" placeholder="Search for a table" onChange={(e) => setSearchText(e.target.value)} value={searchText} size="tiny" actions={ searchText && ( setSearchText('')} /> ) } />
{/* List of tables belonging to selected schema */} {schemaTables.length > 0 && ( )} {/* List of views belonging to selected schema */} {filteredSchemaViews.length > 0 && (
All Views
{schemaViews.map((view: SchemaView) => { const viewId = Base64.encode(JSON.stringify(view)) const isActive = id === viewId return (
{view.name}
) })}
)} {searchText.length > 0 && schemaTables.length === 0 && filteredSchemaViews.length === 0 && (
No tables or views found
)} {searchText.length === 0 && schemaTables.length === 0 && filteredSchemaViews.length === 0 && (
No tables available
)}
) } export default TableEditorMenu