multimodalart's picture
Upload 121 files
f555806 verified
'use client';
import { useEffect, useState, use, useMemo } from 'react';
import { LuImageOff, LuLoader, LuBan } from 'react-icons/lu';
import { FaChevronLeft } from 'react-icons/fa';
import DatasetImageCard from '@/components/DatasetImageCard';
import { Button } from '@headlessui/react';
import AddImagesModal, { openImagesModal } from '@/components/AddImagesModal';
import { TopBar, MainContent } from '@/components/layout';
import { apiClient } from '@/utils/api';
import FullscreenDropOverlay from '@/components/FullscreenDropOverlay';
import { useRouter } from 'next/navigation';
import { usingBrowserDb } from '@/utils/env';
import { hasUserDataset } from '@/utils/storage/datasetStorage';
import { useAuth } from '@/contexts/AuthContext';
import HFLoginButton from '@/components/HFLoginButton';
import Link from 'next/link';
export default function DatasetPage({ params }: { params: { datasetName: string } }) {
const [imgList, setImgList] = useState<{ img_path: string }[]>([]);
const usableParams = use(params as any) as { datasetName: string };
const datasetName = usableParams.datasetName;
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const router = useRouter();
const { status: authStatus } = useAuth();
const isAuthenticated = authStatus === 'authenticated';
const hasDatasetEntry = !usingBrowserDb || hasUserDataset(datasetName);
const allowAccess = hasDatasetEntry && isAuthenticated;
const refreshImageList = (dbName: string) => {
setStatus('loading');
console.log('Fetching images for dataset:', dbName);
apiClient
.post('/api/datasets/listImages', { datasetName: dbName })
.then((res: any) => {
const data = res.data;
console.log('Images:', data.images);
// sort
data.images.sort((a: { img_path: string }, b: { img_path: string }) => a.img_path.localeCompare(b.img_path));
setImgList(data.images);
setStatus('success');
})
.catch(error => {
console.error('Error fetching images:', error);
setStatus('error');
});
};
useEffect(() => {
if (!datasetName) {
return;
}
if (!isAuthenticated) {
return;
}
if (!hasDatasetEntry) {
setImgList([]);
setStatus('error');
router.replace('/datasets');
return;
}
refreshImageList(datasetName);
}, [datasetName, hasDatasetEntry, isAuthenticated, router]);
if (!allowAccess) {
return (
<>
<TopBar>
<div>
<Button className="text-gray-500 dark:text-gray-300 px-3 mt-1" onClick={() => history.back()}>
<FaChevronLeft />
</Button>
</div>
<div>
<h1 className="text-lg">Dataset: {datasetName}</h1>
</div>
<div className="flex-1"></div>
</TopBar>
<MainContent>
<div className="border border-gray-800 rounded-lg p-6 bg-gray-900 text-gray-400 text-sm flex flex-col gap-4">
<p>You need to sign in with Hugging Face or provide a valid token to view this dataset.</p>
<div className="flex items-center gap-3">
<HFLoginButton size="sm" />
<Link href="/settings" className="text-xs text-blue-400 hover:text-blue-300">
Manage authentication in Settings
</Link>
</div>
</div>
</MainContent>
</>
);
}
const PageInfoContent = useMemo(() => {
let icon = null;
let text = '';
let subtitle = '';
let showIt = false;
let bgColor = '';
let textColor = '';
let iconColor = '';
if (status == 'loading') {
icon = <LuLoader className="animate-spin w-8 h-8" />;
text = 'Loading Images';
subtitle = 'Please wait while we fetch your dataset images...';
showIt = true;
bgColor = 'bg-gray-50 dark:bg-gray-800/50';
textColor = 'text-gray-900 dark:text-gray-100';
iconColor = 'text-gray-500 dark:text-gray-400';
}
if (status == 'error') {
icon = <LuBan className="w-8 h-8" />;
text = 'Error Loading Images';
subtitle = 'There was a problem fetching the images. Please try refreshing the page.';
showIt = true;
bgColor = 'bg-red-50 dark:bg-red-950/20';
textColor = 'text-red-900 dark:text-red-100';
iconColor = 'text-red-600 dark:text-red-400';
}
if (status == 'success' && imgList.length === 0) {
icon = <LuImageOff className="w-8 h-8" />;
text = 'No Images Found';
subtitle = 'This dataset is empty. Click "Add Images" to get started.';
showIt = true;
bgColor = 'bg-gray-50 dark:bg-gray-800/50';
textColor = 'text-gray-900 dark:text-gray-100';
iconColor = 'text-gray-500 dark:text-gray-400';
}
if (!showIt) return null;
return (
<div
className={`mt-10 flex flex-col items-center justify-center py-16 px-8 rounded-xl border-2 border-gray-700 border-dashed ${bgColor} ${textColor} mx-auto max-w-md text-center`}
>
<div className={`${iconColor} mb-4`}>{icon}</div>
<h3 className="text-lg font-semibold mb-2">{text}</h3>
<p className="text-sm opacity-75 leading-relaxed">{subtitle}</p>
</div>
);
}, [status, imgList.length]);
return (
<>
{/* Fixed top bar */}
<TopBar>
<div>
<Button className="text-gray-500 dark:text-gray-300 px-3 mt-1" onClick={() => history.back()}>
<FaChevronLeft />
</Button>
</div>
<div>
<h1 className="text-lg">Dataset: {datasetName}</h1>
</div>
<div className="flex-1"></div>
<div>
<Button
className="text-gray-200 bg-slate-600 px-3 py-1 rounded-md"
onClick={() => openImagesModal(datasetName, () => refreshImageList(datasetName))}
>
Add Images
</Button>
</div>
</TopBar>
<MainContent>
{PageInfoContent}
{status === 'success' && imgList.length > 0 && (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{imgList.map(img => (
<DatasetImageCard
key={img.img_path}
alt="image"
imageUrl={img.img_path}
onDelete={() => refreshImageList(datasetName)}
/>
))}
</div>
)}
</MainContent>
<AddImagesModal />
<FullscreenDropOverlay
datasetName={datasetName}
onComplete={() => refreshImageList(datasetName)}
/>
</>
);
}