Xianbao QIAN
use client side rendering for the homepage.
c80b461
raw
history blame
4.58 kB
'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('');
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);
}
fetchData();
}, []);
const filteredModels = allModels.filter((model) =>
model.ancestor.toLowerCase().includes(filterText.toLowerCase())
);
const totalPages = Math.ceil(filteredModels.length / pageSize);
const paginatedModels = filteredModels.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);
return (
<main className="container mx-auto py-8 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 rounded-md"
/>
</div>
{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">Direct Children</th>
<th className="px-4 py-2 bg-gray-100 dark:bg-gray-800 text-right">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">
<button
onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))}
disabled={currentPage === 1}
className="px-4 py-2 bg-blue-500 text-white rounded-md mr-2"
>
Previous
</button>
<button
onClick={() => setCurrentPage((prev) => Math.min(prev + 1, totalPages))}
disabled={currentPage === totalPages}
className="px-4 py-2 bg-blue-500 text-white rounded-md"
>
Next
</button>
</div>
</>
) : (
<p>No data found.</p>
)}
</main>
);
}