Spaces:
Build error
Build error
'use client'; | |
import { useState, useEffect } from 'react'; | |
import * as duckdb from '@duckdb/duckdb-wasm'; | |
type ModelData = { | |
ancestor: string; | |
direct_children: string[] | null; | |
all_children: string[]; | |
all_children_count: number; | |
direct_children_count: number | null; | |
}; | |
export default function Home() { | |
const [allModels, setAllModels] = useState<ModelData[]>([]); | |
const [currentPage, setCurrentPage] = useState(1); | |
const [pageSize, setPageSize] = useState(100); | |
const [filterText, setFilterText] = useState(''); | |
const [isLoading, setIsLoading] = useState(true); | |
const [orderBy, setOrderBy] = useState<'all_children' | 'direct_children'>('all_children'); | |
useEffect(() => { | |
async function fetchData() { | |
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles(); | |
// Select a bundle based on browser checks | |
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES); | |
const worker_url = URL.createObjectURL( | |
new Blob([`importScripts("${bundle.mainWorker!}");`], { type: 'text/javascript' }) | |
); | |
// Instantiate the asynchronous version of DuckDB-Wasm | |
const worker = new Worker(worker_url); | |
const logger = new duckdb.ConsoleLogger(); | |
const db = new duckdb.AsyncDuckDB(logger, worker); | |
await db.instantiate(bundle.mainModule, bundle.pthreadWorker); | |
// Register the Parquet file using the URL | |
await db.registerFileURL( | |
'ancestor_children.parquet', | |
`${window.location.origin}/ancestor_children.parquet`, | |
duckdb.DuckDBDataProtocol.HTTP, | |
false | |
); | |
// Execute the SQL query using the registered Parquet file | |
const query = ` | |
SELECT | |
ancestor, | |
direct_children, | |
all_children, | |
CAST(all_children_count AS INTEGER) AS all_children_count, | |
CAST(direct_children_count AS INTEGER) AS direct_children_count | |
FROM 'ancestor_children.parquet' | |
`; | |
const conn = await db.connect(); | |
const result = await conn.query(query); | |
// Convert the result to a JavaScript array | |
const data: ModelData[] = result.toArray(); | |
// Close the connection and terminate the worker | |
await conn.close(); | |
await db.terminate(); | |
setAllModels(data); | |
setIsLoading(false); | |
} | |
fetchData(); | |
}, []); | |
const filteredModels = allModels.filter((model) => | |
model.ancestor.toLowerCase().includes(filterText.toLowerCase()) | |
); | |
const sortedModels = filteredModels.sort((a, b) => { | |
if (orderBy === 'all_children') { | |
return b.all_children_count - a.all_children_count; | |
} else { | |
return (b.direct_children_count ?? 0) - (a.direct_children_count ?? 0); | |
} | |
}); | |
const totalPages = Math.ceil(sortedModels.length / pageSize); | |
const paginatedModels = sortedModels.slice( | |
(currentPage - 1) * pageSize, | |
currentPage * pageSize | |
); | |
const handleOrderByClick = (column: 'all_children' | 'direct_children') => { | |
setOrderBy(column); | |
setCurrentPage(1); | |
}; | |
return ( | |
<main className="container mx-auto py-8 bg-white dark:bg-gray-900 text-gray-900 dark:text-white"> | |
<h1 className="text-4xl font-bold mb-4">All Models</h1> | |
<div className="mb-4"> | |
<input | |
type="text" | |
placeholder="Filter by model name" | |
value={filterText} | |
onChange={(e) => setFilterText(e.target.value)} | |
className="px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-white" | |
/> | |
</div> | |
{isLoading ? ( | |
<p>Loading data...</p> | |
) : paginatedModels.length > 0 ? ( | |
<> | |
<table className="table-auto border-collapse w-full"> | |
<thead> | |
<tr> | |
<th className="px-4 py-2 bg-gray-100 dark:bg-gray-800 text-left">Model</th> | |
<th | |
className="px-4 py-2 bg-gray-100 dark:bg-gray-800 text-right cursor-pointer" | |
onClick={() => handleOrderByClick('direct_children')} | |
> | |
Direct Children {orderBy === 'direct_children' && '▼'} | |
</th> | |
<th | |
className="px-4 py-2 bg-gray-100 dark:bg-gray-800 text-right cursor-pointer" | |
onClick={() => handleOrderByClick('all_children')} | |
> | |
All Children {orderBy === 'all_children' && '▼'} | |
</th> | |
</tr> | |
</thead> | |
<tbody> | |
{paginatedModels.map((model, index) => ( | |
<tr key={index} className="border-t border-gray-200 dark:border-gray-700"> | |
<td className="px-4 py-2">{model.ancestor}</td> | |
<td className="px-4 py-2 text-right">{model.direct_children_count ?? 0}</td> | |
<td className="px-4 py-2 text-right">{model.all_children_count}</td> | |
</tr> | |
))} | |
</tbody> | |
</table> | |
<div className="mt-4 flex items-center justify-between"> | |
<button | |
onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))} | |
disabled={currentPage === 1} | |
className="px-4 py-2 bg-blue-500 dark:bg-blue-600 text-white rounded-md mr-2" | |
> | |
Previous | |
</button> | |
<div className="flex items-center space-x-2"> | |
{currentPage > 1 && ( | |
<> | |
<button | |
onClick={() => setCurrentPage(1)} | |
className="px-2 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-200 rounded-md" | |
> | |
1 | |
</button> | |
{currentPage > 2 && <span className="text-gray-500">...</span>} | |
</> | |
)} | |
{[...Array(5)].map((_, i) => { | |
const page = currentPage + i - 2; | |
if (page >= 1 && page <= totalPages) { | |
return ( | |
<button | |
key={page} | |
onClick={() => setCurrentPage(page)} | |
className={`px-2 py-1 ${ | |
page === currentPage | |
? 'bg-blue-500 dark:bg-blue-600 text-white' | |
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-200' | |
} rounded-md`} | |
> | |
{page} | |
</button> | |
); | |
} | |
return null; | |
})} | |
{currentPage < totalPages && ( | |
<> | |
{currentPage < totalPages - 1 && <span className="text-gray-500">...</span>} | |
<button | |
onClick={() => setCurrentPage(totalPages)} | |
className="px-2 py-1 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-200 rounded-md" | |
> | |
{totalPages} | |
</button> | |
</> | |
)} | |
</div> | |
<button | |
onClick={() => setCurrentPage((prev) => Math.min(prev + 1, totalPages))} | |
disabled={currentPage === totalPages} | |
className="px-4 py-2 bg-blue-500 dark:bg-blue-600 text-white rounded-md" | |
> | |
Next | |
</button> | |
</div> | |
</> | |
) : ( | |
<p>No data found.</p> | |
)} | |
</main> | |
); | |
} | |