The installation may currently fail. We recommend copying the code below and creating the extension manually in Eidos.
By: Mayne
view the table structure of a specified table, and the column names of fields in the database
import React, { useEffect, useState } from "react";
import { Database, Columns, Search, ChevronDown, Check } from "lucide-react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command";
import { cn } from "@/lib/utils";
export default function SchemaInspector() {
const [tables, setTables] = useState([]);
const [selectedTable, setSelectedTable] = useState(null);
const [columns, setColumns] = useState([]);
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
useEffect(() => {
eidos.currentSpace.tree.findMany({ where: { type: "table" } }).then(setTables);
}, []);
const loadTableSchema = async (tableId) => {
if (!tableId) {
setSelectedTable(null);
setColumns([]);
return;
}
setLoading(true);
try {
const tableColumns = await eidos.currentSpace.column.findMany({
where: { table_name: `tb_${tableId}` }
});
setColumns(tableColumns);
setSelectedTable(tableId);
} catch (error) {
console.error("Failed to load columns:", error);
} finally {
setLoading(false);
}
};
const handleTableSelect = (tableId) => {
loadTableSchema(tableId);
setOpen(false);
};
return (
<div className="min-h-screen bg-gray-50">
<div className="max-w-6xl mx-auto px-6 py-8">
<div className="mb-8">
<h1 className="text-3xl font-light tracking-tight text-gray-900 mb-1">
Schema Inspector
</h1>
<p className="text-gray-600">
Explore your database structure
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-1">
<div className="space-y-3">
<div className="relative">
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<button className="w-full h-12 bg-white border-0 shadow-sm rounded-xl px-4 text-left flex items-center justify-between hover:shadow-md transition-shadow">
<span className="text-gray-900">
{selectedTable ? (tables.find(t => t.id === selectedTable)?.name || "Untitled") : "Select a table..."}
</span>
<ChevronDown className="w-4 h-4 text-gray-400" />
</button>
</PopoverTrigger>
<PopoverContent className="w-[var(--radix-popover-trigger-width)] p-0" align="start">
<Command>
<CommandInput
placeholder="Search tables..."
className="h-12 border-0 focus:ring-0"
/>
<CommandEmpty className="py-6 text-center text-sm text-gray-500">
No tables found
</CommandEmpty>
<CommandGroup className="max-h-64 overflow-auto">
{tables.map((table) => (
<CommandItem
key={table.id}
value={table.name || "Untitled"}
onSelect={() => handleTableSelect(table.id)}
className="py-3 px-4 cursor-pointer"
>
<Check
className={cn(
"mr-2 h-4 w-4",
selectedTable === table.id ? "opacity-100" : "opacity-0"
)}
/>
{table.name || "Untitled"}
</CommandItem>
))}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
</div>
<div className="mt-12">
<div className="text-sm text-gray-500 mb-4">
{tables.length} tables available
</div>
</div>
</div>
</div>
<div className="lg:col-span-2">
<div className="bg-white rounded-xl shadow-sm">
<div className="p-6">
<div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-light text-gray-900">
{selectedTable ? (tables.find(t => t.id === selectedTable)?.name || "Untitled") : "No table selected"}
</h2>
<div className="text-sm text-gray-500">
{columns.length} {columns.length === 1 ? 'field' : 'fields'}
</div>
</div>
{loading && (
<div className="flex items-center justify-center py-16">
<div className="text-gray-400">Loading...</div>
</div>
)}
{!loading && selectedTable && columns.length === 0 && (
<div className="text-center py-16">
<div className="text-gray-400 mb-2">No fields found</div>
<div className="text-sm text-gray-500">This table appears to be empty</div>
</div>
)}
{!loading && selectedTable && columns.length > 0 && (
<div className="space-y-3">
{columns.map((column) => (
<div key={column.id} className="border-b border-gray-100 pb-4 last:border-0">
<div className="flex items-start justify-between mb-3">
<div>
<h3 className="text-lg font-medium text-gray-900 mb-1">
{column.name}
</h3>
<div className="text-sm text-gray-500">
{column.field}
</div>
</div>
<div className="text-sm font-mono text-gray-600 bg-gray-50 px-3 py-1 rounded-full">
{column.type}
</div>
</div>
<div className="space-y-2 text-sm">
<div className="text-gray-600">
<span className="text-gray-400">Column:</span> {column.table_column_name}
</div>
{column.options && (
<div className="text-gray-600">
<span className="text-gray-400">Options:</span> {JSON.stringify(column.options)}
</div>
)}
{column.description && (
<div className="text-gray-600">
<span className="text-gray-400">Description:</span> {column.description}
</div>
)}
</div>
</div>
))}
</div>
)}
{!selectedTable && (
<div className="text-center py-16">
<Database className="w-12 h-12 text-gray-300 mx-auto mb-4" />
<div className="text-gray-400">Select a table to explore its structure</div>
</div>
)}
</div>
</div>
</div>
</div>
</div>
</div>
);
}