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"; import { useI18n } from "@/i18n"; 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", completed: "destructive", }; export default function CronPage() { const [jobs, setJobs] = useState([]); const [loading, setLoading] = useState(true); const { toast, showToast } = useToast(); const { t } = useI18n(); // 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(t.common.loading, "error")) .finally(() => setLoading(false)); }; useEffect(() => { loadJobs(); }, []); const handleCreate = async () => { if (!prompt.trim() || !schedule.trim()) { showToast(`${t.cron.prompt} & ${t.cron.schedule} required`, "error"); return; } setCreating(true); try { await api.createCronJob({ prompt: prompt.trim(), schedule: schedule.trim(), name: name.trim() || undefined, deliver, }); showToast(t.common.create + " ✓", "success"); setPrompt(""); setSchedule(""); setName(""); setDeliver("local"); loadJobs(); } catch (e) { showToast(`${t.config.failedToSave}: ${e}`, "error"); } finally { setCreating(false); } }; const handlePauseResume = async (job: CronJob) => { try { const isPaused = job.state === "paused"; if (isPaused) { await api.resumeCronJob(job.id); showToast(`${t.cron.resume}: "${job.name || job.prompt.slice(0, 30)}"`, "success"); } else { await api.pauseCronJob(job.id); showToast(`${t.cron.pause}: "${job.name || job.prompt.slice(0, 30)}"`, "success"); } loadJobs(); } catch (e) { showToast(`${t.status.error}: ${e}`, "error"); } }; const handleTrigger = async (job: CronJob) => { try { await api.triggerCronJob(job.id); showToast(`${t.cron.triggerNow}: "${job.name || job.prompt.slice(0, 30)}"`, "success"); loadJobs(); } catch (e) { showToast(`${t.status.error}: ${e}`, "error"); } }; const handleDelete = async (job: CronJob) => { try { await api.deleteCronJob(job.id); showToast(`${t.common.delete}: "${job.name || job.prompt.slice(0, 30)}"`, "success"); loadJobs(); } catch (e) { showToast(`${t.status.error}: ${e}`, "error"); } }; if (loading) { return (
); } return (
{/* Create new job form */} {t.cron.newJob}
setName(e.target.value)} />