Dataset uploads working

This commit is contained in:
Jaret Burkett
2025-02-20 12:47:01 -07:00
parent b5252b5028
commit 9f6030620f
9 changed files with 565 additions and 33 deletions

View File

@@ -0,0 +1,55 @@
// src/app/api/datasets/upload/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { writeFile, mkdir } from 'fs/promises';
import { join } from 'path';
import { getDatasetsRoot } from '@/app/api/datasets/utils';
export async function POST(request: NextRequest) {
try {
const datasetsPath = await getDatasetsRoot();
if (!datasetsPath) {
return NextResponse.json({ error: 'Datasets path not found' }, { status: 500 });
}
const formData = await request.formData();
const files = formData.getAll('files');
const datasetName = formData.get('datasetName') as string;
if (!files || files.length === 0) {
return NextResponse.json({ error: 'No files provided' }, { status: 400 });
}
// Create upload directory if it doesn't exist
const uploadDir = join(datasetsPath, datasetName);
await mkdir(uploadDir, { recursive: true });
const savedFiles = await Promise.all(
files.map(async (file: any) => {
const bytes = await file.arrayBuffer();
const buffer = Buffer.from(bytes);
// Clean filename and ensure it's unique
const fileName = file.name.replace(/[^a-zA-Z0-9.-]/g, '_');
const filePath = join(uploadDir, fileName);
await writeFile(filePath, buffer);
return fileName;
}),
);
return NextResponse.json({
message: 'Files uploaded successfully',
files: savedFiles,
});
} catch (error) {
console.error('Upload error:', error);
return NextResponse.json({ error: 'Error uploading files' }, { status: 500 });
}
}
// Increase payload size limit (default is 4mb)
export const config = {
api: {
bodyParser: false,
responseLimit: '50mb',
},
};

View File

@@ -1,19 +1,15 @@
'use client';
import { useEffect, useState, use } from 'react';
import Card from '@/components/Card';
import { Modal } from '@/components/Modal';
import Link from 'next/link';
import { TextInput } from '@/components/formInputs';
import { useRouter } from 'next/router';
import { FaChevronLeft } from 'react-icons/fa';
import DatasetImageCard from '@/components/DatasetImageCard';
import { Button } from '@headlessui/react';
import AddImagesModal, { openImagesModal } from '@/components/AddImagesModal';
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 [newDatasetName, setNewDatasetName] = useState('');
const [isNewDatasetModalOpen, setIsNewDatasetModalOpen] = useState(false);
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const refreshImageList = (dbName: string) => {
@@ -43,31 +39,42 @@ export default function DatasetPage({ params }: { params: { datasetName: string
refreshImageList(datasetName);
}
}, [datasetName]);
return (
<>
<div className="space-y-6">
<div className="flex justify-between items-center">
<div>
<h1 className="text-xl font-bold mb-8">Dataset: {datasetName}</h1>
</div>
{/* Fixed top bar */}
<div className="absolute top-0 left-0 w-full h-12 dark:bg-gray-900 shadow-sm z-10 flex items-center px-2">
<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>
<Card title={`Images (${imgList.length})`}>
{status === 'loading' && <p>Loading...</p>}
{status === 'error' && <p>Error fetching images</p>}
{status === 'success' && (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{imgList.length === 0 && <p>No images found</p>}
{imgList.map(img => (
<DatasetImageCard
key={img.img_path}
alt="image"
imageUrl={img.img_path}
/>
))}
</div>
)}
</Card>
</div>
<div className="pt-16 px-6 absolute top-0 left-0 w-full h-full overflow-auto">
{status === 'loading' && <p>Loading...</p>}
{status === 'error' && <p>Error fetching images</p>}
{status === 'success' && (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{imgList.length === 0 && <p>No images found</p>}
{imgList.map(img => (
<DatasetImageCard key={img.img_path} alt="image" imageUrl={img.img_path} />
))}
</div>
)}
</div>
<AddImagesModal />
</>
);
}

View File

@@ -19,7 +19,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<ThemeProvider>
<div className="flex h-screen bg-gray-950">
<Sidebar />
<main className="flex-1 p-8 overflow-auto bg-gray-950 text-gray-100">{children}</main>
<main className="flex-1 p-8 overflow-auto bg-gray-950 text-gray-100 relative">{children}</main>
</div>
</ThemeProvider>
<ConfirmModal />