John-Jiang's picture
init commit
5301c48
raw
history blame
12 kB
'use client'
import { useState, useEffect } from 'react'
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Eye, Calendar, ChevronDown, ChevronUp } from 'lucide-react'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
interface Dataset {
id: string
name: string
created_at: string
record_count: number
status: 'completed' | 'processing' | 'failed'
data: any[]
}
interface DatasetViewerProps {
projectId: string
datasetType: 'factory' | 'template'
}
export default function DatasetViewer({ projectId, datasetType }: DatasetViewerProps) {
const [datasets, setDatasets] = useState<Dataset[]>([])
const [selectedDataset, setSelectedDataset] = useState<Dataset | null>(null)
const [datasetData, setDatasetData] = useState<any[]>([])
const [loading, setLoading] = useState(true)
const [viewingData, setViewingData] = useState(false)
const [isDatasetListOpen, setIsDatasetListOpen] = useState(true)
const [currentPage, setCurrentPage] = useState(1)
const recordsPerPage = 2
useEffect(() => {
fetchDatasets()
}, [projectId, datasetType])
const fetchDatasets = async () => {
try {
setLoading(true)
// Replace with your actual API endpoint
const response = await fetch(`/api/dataset/list`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
projectId: projectId,
datasetType: datasetType,
}),
})
const data = await response.json()
// Ensure data is always an array
setDatasets(Array.isArray(data) ? data : [])
} catch (error) {
console.error('Error fetching datasets:', error)
setDatasets([])
} finally {
setLoading(false)
}
}
const viewDataset = async (dataset: Dataset) => {
try {
setViewingData(true)
setSelectedDataset(dataset)
setCurrentPage(1) // Reset to first page when viewing new dataset
const dataset_data = datasets.find((d) => d.id === dataset.id)?.data
// Replace with your actual API endpoint
// const response = await fetch(`/api/dataset/get`, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({
// projectId: projectId,
// datasetName: dataset.name,
// }),
// })
// const data = await response.json()
setDatasetData(dataset_data || [])
} catch (error) {
console.error('Error fetching dataset data:', error)
setDatasetData([])
} finally {
setViewingData(false)
}
}
// Pagination calculations
const totalPages = Math.ceil(datasetData.length / recordsPerPage)
const startIndex = (currentPage - 1) * recordsPerPage
const endIndex = startIndex + recordsPerPage
const currentPageData = datasetData.slice(startIndex, endIndex)
const goToPage = (page: number) => {
setCurrentPage(Math.max(1, Math.min(page, totalPages)))
}
if (loading) {
return (
<div className="flex justify-center items-center py-12">
<div className="text-gray-500">Loading datasets...</div>
</div>
)
}
if (datasets.length === 0) {
return (
<div className="text-center py-12">
<p className="text-gray-500">
No {datasetType === 'factory' ? 'data factory' : 'data template'} datasets found for this project
</p>
</div>
)
}
return (
<div className="space-y-6">
{/* Collapsible Dataset List */}
<Collapsible open={isDatasetListOpen} onOpenChange={setIsDatasetListOpen}>
<Card>
<CollapsibleTrigger asChild>
<CardHeader className="cursor-pointer hover:bg-gray-50 transition-colors">
<div className="flex items-center justify-between">
<CardTitle>Available Datasets</CardTitle>
<div className="flex items-center gap-2">
<span className="text-sm text-gray-500">
{datasets.length} dataset{datasets.length !== 1 ? 's' : ''}
</span>
{isDatasetListOpen ? (
<ChevronUp className="h-4 w-4" />
) : (
<ChevronDown className="h-4 w-4" />
)}
</div>
</div>
</CardHeader>
</CollapsibleTrigger>
<CollapsibleContent>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Created</TableHead>
<TableHead>Records</TableHead>
<TableHead>Status</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{Array.isArray(datasets) && datasets.map((dataset) => (
<TableRow key={dataset.id}>
<TableCell className="font-medium">{dataset.name}</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<Calendar className="h-4 w-4 text-gray-400" />
{(() => {
if (!dataset.created_at) return 'N/A'
// Parse yyyy-mm-dd_hh-mm-ss format
const [datePart, timePart] = dataset.created_at.split('_')
if (!datePart || !timePart) return dataset.created_at
const [year, month, day] = datePart.split('-')
const [hours, minutes, seconds] = timePart.split('-')
const dateStr = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`
return new Date(dateStr).toLocaleString()
})()}
</div>
</TableCell>
<TableCell>{dataset.record_count.toLocaleString()}</TableCell>
<TableCell>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${
dataset.status === 'completed' ? 'bg-green-100 text-green-800' :
dataset.status === 'processing' ? 'bg-yellow-100 text-yellow-800' :
'bg-red-100 text-red-800'
}`}>
{dataset.status}
</span>
</TableCell>
<TableCell>
<Button
variant="outline"
size="sm"
onClick={() => viewDataset(dataset)}
disabled={dataset.status !== 'completed'}
>
<Eye className="h-4 w-4 mr-1" />
View
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</CollapsibleContent>
</Card>
</Collapsible>
{/* Dataset Data Viewer with Pagination */}
{selectedDataset && (
<Card>
<CardHeader>
<CardTitle>Dataset: {selectedDataset.name}</CardTitle>
</CardHeader>
<CardContent>
{viewingData ? (
<div className="flex justify-center items-center py-8">
<div className="text-gray-500">Loading dataset data...</div>
</div>
) : datasetData.length > 0 ? (
<div className="space-y-4">
<div className="overflow-x-auto">
<Table>
<TableHeader>
<TableRow>
<TableHead>id</TableHead>
{Object.keys(datasetData[0] || {}).filter(key => key !== 'id').map((key) => (
<TableHead key={key}>{key}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{currentPageData.map((record, index) => (
<TableRow key={startIndex + index}>
<TableCell className="max-w-xs truncate">
{typeof record.id === 'object' ? JSON.stringify(record.id) : String(record.id)}
</TableCell>
{Object.entries(record).filter(([key]) => key !== 'id').map(([key, value], cellIndex) => (
<TableCell key={cellIndex} className="max-w-xs truncate">
{typeof value === 'object' ? JSON.stringify(value) : String(value)}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
{/* Pagination Controls */}
{totalPages > 1 && (
<div className="flex items-center justify-between">
<div className="text-sm text-gray-500">
Showing {startIndex + 1}-{Math.min(endIndex, datasetData.length)} of {datasetData.length} records
</div>
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => goToPage(currentPage - 1)}
disabled={currentPage === 1}
>
Previous
</Button>
<div className="flex items-center gap-1">
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
let pageNum;
if (totalPages <= 5) {
pageNum = i + 1;
} else if (currentPage <= 3) {
pageNum = i + 1;
} else if (currentPage >= totalPages - 2) {
pageNum = totalPages - 4 + i;
} else {
pageNum = currentPage - 2 + i;
}
return (
<Button
key={pageNum}
variant={currentPage === pageNum ? "default" : "outline"}
size="sm"
onClick={() => goToPage(pageNum)}
className="w-8 h-8 p-0"
>
{pageNum}
</Button>
);
})}
</div>
<Button
variant="outline"
size="sm"
onClick={() => goToPage(currentPage + 1)}
disabled={currentPage === totalPages}
>
Next
</Button>
</div>
</div>
)}
</div>
) : (
<div className="text-center py-8 text-gray-500">
No data available for this dataset
</div>
)}
</CardContent>
</Card>
)}
</div>
)
}