"use client"; import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Header } from "@/components/header"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { FolderKanban, Upload, Trash2, Package, AlertCircle, } from "lucide-react"; import { ListProjects, ListVersions } from "@/lib/types"; export default function ProjectsPage() { const queryClient = useQueryClient(); const [selectedProject, setSelectedProject] = useState(null); const [uploadDialogOpen, setUploadDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); // Fetch projects const { data: projects, isLoading: isProjectsLoading } = useQuery({ queryKey: ["projects"], queryFn: async (): Promise => { const res = await fetch("/api/scrapyd/projects"); if (!res.ok) throw new Error("Failed to fetch projects"); return res.json(); }, }); // Fetch versions for selected project const { data: versions } = useQuery({ queryKey: ["versions", selectedProject], queryFn: async (): Promise => { const res = await fetch( `/api/scrapyd/versions?project=${selectedProject}` ); if (!res.ok) throw new Error("Failed to fetch versions"); return res.json(); }, enabled: !!selectedProject, }); // Delete project mutation const deleteProjectMutation = useMutation({ mutationFn: async (project: string) => { const res = await fetch("/api/scrapyd/projects", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ project }), }); if (!res.ok) throw new Error("Failed to delete project"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["projects"] }); setDeleteDialogOpen(false); setSelectedProject(null); }, }); // Upload version mutation const uploadVersionMutation = useMutation({ mutationFn: async (formData: FormData) => { const res = await fetch("/api/scrapyd/versions", { method: "POST", body: formData, }); if (!res.ok) throw new Error("Failed to upload version"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["projects"] }); queryClient.invalidateQueries({ queryKey: ["versions"] }); setUploadDialogOpen(false); }, }); const handleUpload = (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); uploadVersionMutation.mutate(formData); }; return (
Upload Project Version Upload a Python egg file for your Scrapy project
} /> {/* Projects List */} All Projects {isProjectsLoading ? (
{[1, 2, 3].map((i) => ( ))}
) : projects?.projects && projects.projects.length > 0 ? (
Project Name Versions Actions {projects.projects.map((project) => ( setSelectedProject(project)} className="cursor-pointer" >
{project}
{selectedProject === project && versions ? ( {versions.versions.length} version(s) ) : ( Click to load )} { setDeleteDialogOpen(open); if (open) setSelectedProject(project); }} > Delete Project Are you sure you want to delete "{project}"? This action cannot be undone.
))}
) : (

No projects found

Upload your first project to get started

)}
{/* Project Versions */} {selectedProject && versions && ( Versions for "{selectedProject}" {versions.versions.length > 0 ? (
{versions.versions.map((version) => (
{version}
{version === versions.versions[versions.versions.length - 1] ? "Latest" : ""}
))}
) : (

No versions found for this project

)}
)}
); }