import { useEffect, useState } from "react"; import { Clock, Pause, Play, Plus, Trash2, Zap } from "lucide-react"; import { api } from "@/lib/api"; import type { CronJob } from "@/lib/api"; import { useToast } from "@/hooks/useToast"; import { Toast } from "@/components/Toast"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select } from "@/components/ui/select"; function formatTime(iso?: string | null): string { if (!iso) return "—"; const d = new Date(iso); return d.toLocaleString(); } const STATUS_VARIANT: Record = { enabled: "success", scheduled: "success", paused: "warning", error: "destructive", exhausted: "destructive", }; export default function CronPage() { const [jobs, setJobs] = useState([]); const [loading, setLoading] = useState(true); const { toast, showToast } = useToast(); // New job form state const [prompt, setPrompt] = useState(""); const [schedule, setSchedule] = useState(""); const [name, setName] = useState(""); const [deliver, setDeliver] = useState("local"); const [creating, setCreating] = useState(false); const loadJobs = () => { api .getCronJobs() .then(setJobs) .catch(() => showToast("Failed to load cron jobs", "error")) .finally(() => setLoading(false)); }; useEffect(() => { loadJobs(); }, []); const handleCreate = async () => { if (!prompt.trim() || !schedule.trim()) { showToast("Prompt and schedule are required", "error"); return; } setCreating(true); try { await api.createCronJob({ prompt: prompt.trim(), schedule: schedule.trim(), name: name.trim() || undefined, deliver, }); showToast("Cron job created", "success"); setPrompt(""); setSchedule(""); setName(""); setDeliver("local"); loadJobs(); } catch (e) { showToast(`Failed to create job: ${e}`, "error"); } finally { setCreating(false); } }; const handlePauseResume = async (job: CronJob) => { try { const isPaused = job.state === "paused"; if (isPaused) { await api.resumeCronJob(job.id); showToast(`Resumed "${job.name || job.prompt.slice(0, 30)}"`, "success"); } else { await api.pauseCronJob(job.id); showToast(`Paused "${job.name || job.prompt.slice(0, 30)}"`, "success"); } loadJobs(); } catch (e) { showToast(`Action failed: ${e}`, "error"); } }; const handleTrigger = async (job: CronJob) => { try { await api.triggerCronJob(job.id); showToast(`Triggered "${job.name || job.prompt.slice(0, 30)}"`, "success"); loadJobs(); } catch (e) { showToast(`Trigger failed: ${e}`, "error"); } }; const handleDelete = async (job: CronJob) => { try { await api.deleteCronJob(job.id); showToast(`Deleted "${job.name || job.prompt.slice(0, 30)}"`, "success"); loadJobs(); } catch (e) { showToast(`Delete failed: ${e}`, "error"); } }; if (loading) { return (
); } return (
{/* Create new job form */} New Cron Job
setName(e.target.value)} />