"use client";
import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
import { ArrowLeft, Clock, AlertTriangle, Pause, Play, Trash2 } from "lucide-react";
import { toast } from "sonner";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import {
useCronjob,
useDeleteCronjob,
useUpdateCronjobStatus,
} from "@/hooks/use-cronjobs";
import { useAvailableMcps, useUserIntegrations } from "@/hooks/use-integrations";
export const Route = createFileRoute("/painel/cronjobs/$id")({
component: CronjobDetailPage,
});
function CronjobDetailPage() {
const { id } = Route.useParams();
const navigate = useNavigate();
const { data: job, isLoading, error } = useCronjob(id);
const { data: mcps = [] } = useAvailableMcps();
const { data: integrations = [] } = useUserIntegrations();
const updateMut = useUpdateCronjobStatus();
const deleteMut = useDeleteCronjob();
const [confirmDelete, setConfirmDelete] = useState(false);
if (isLoading) {
return
;
}
if (error || !job) {
return (
Automação não encontrada.
);
}
const connectedMcpIds = new Set(
integrations.filter((i) => i.status === "active").map((i) => i.mcp_id),
);
const requiredMcps = job.required_mcp_slugs
.map((slug) => mcps.find((m) => m.slug === slug))
.filter((m): m is NonNullable => !!m);
const missingMcps = requiredMcps.filter((m) => !connectedMcpIds.has(m.id));
const isActive = job.status === "active";
const isAutoPaused = job.status === "auto_paused";
async function toggle() {
try {
await updateMut.mutateAsync({
id: job!.id,
status: isActive ? "paused" : "active",
});
toast.success(isActive ? "Pausada." : "Ativada.");
} catch (e) {
toast.error(e instanceof Error ? e.message : "Erro");
}
}
async function remove() {
try {
await deleteMut.mutateAsync(job!.id);
toast.success("Excluída.");
navigate({ to: "/painel/cronjobs" });
} catch (e) {
toast.error(e instanceof Error ? e.message : "Erro");
}
}
return (
{job.name}
{isActive &&
Ativa}
{job.status === "paused" &&
Pausada}
{isAutoPaused && (
Auto-pausada
)}
{isAutoPaused && job.auto_paused_reason && (
Auto-pausada
{job.auto_paused_reason}
)}
{missingMcps.length > 0 && isActive && (
Integrações necessárias não conectadas:
{missingMcps.map((m) => (
- {m.name}
))}
)}
}
/>
{job.description &&
}
Ação enviada ao agente
{job.action_prompt}
Integrações necessárias
{requiredMcps.length === 0 ? (
Nenhuma.
) : (
{requiredMcps.map((m) => {
const ok = connectedMcpIds.has(m.id);
return (
{m.name} {ok ? "✓" : "(não conectado)"}
);
})}
)}
Excluir automação?
Esta ação remove permanentemente “{job.name}”.
Cancelar
{
e.preventDefault();
remove();
}}
disabled={deleteMut.isPending}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{deleteMut.isPending ? "Excluindo..." : "Excluir"}
);
}
function Section({
label,
value,
mono,
icon,
}: {
label: string;
value: string;
mono?: boolean;
icon?: React.ReactNode;
}) {
return (
);
}