"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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Bug, PlayCircle, AlertCircle } from "lucide-react"; import { ListProjects, ListSpiders, ScheduleJob } from "@/lib/types"; import { Textarea } from "@/components/ui/textarea"; export default function SpidersPage() { const queryClient = useQueryClient(); const [selectedProject, setSelectedProject] = useState(""); const [scheduleDialogOpen, setScheduleDialogOpen] = useState(false); const [selectedSpider, setSelectedSpider] = useState(""); // 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 spiders for selected project const { data: spiders, isLoading: isSpidersLoading } = useQuery({ queryKey: ["spiders", selectedProject], queryFn: async (): Promise => { const res = await fetch( `/api/scrapyd/spiders?project=${selectedProject}` ); if (!res.ok) throw new Error("Failed to fetch spiders"); return res.json(); }, enabled: !!selectedProject, }); // Schedule job mutation const scheduleJobMutation = useMutation({ mutationFn: async (data: { project: string; spider: string; args?: Record; }) => { const res = await fetch("/api/scrapyd/jobs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); if (!res.ok) throw new Error("Failed to schedule job"); return res.json() as Promise; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["jobs"] }); setScheduleDialogOpen(false); setSelectedSpider(""); }, }); const handleSchedule = (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const argsStr = formData.get("args") as string; let args: Record | undefined; if (argsStr.trim()) { try { args = JSON.parse(argsStr); } catch (error) { alert("Invalid JSON format for arguments"); return; } } scheduleJobMutation.mutate({ project: selectedProject, spider: selectedSpider, args, }); }; return (
{/* Project Selector */} Select Project {isProjectsLoading ? ( ) : ( )} {/* Spiders List */} {selectedProject && ( Spiders in "{selectedProject}" {isSpidersLoading ? (
{[1, 2, 3].map((i) => ( ))}
) : spiders?.spiders && spiders.spiders.length > 0 ? (
Spider Name Status Actions {spiders.spiders.map((spider) => (
{spider}
Available { setScheduleDialogOpen(open); if (open) setSelectedSpider(spider); }} >
Schedule Spider Job Schedule "{spider}" to run on "{selectedProject}"