"use client"; import { Button } from "@/components/ui/button"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Play, StopCircle, RefreshCw, Loader2, AlertTriangle, Trash2 } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; import { useState } from "react"; import { controlDeployment, deleteDeployment } from "@/lib/actions/deployment"; // Server Actions import type { DeploymentStatus } from "@/lib/types"; import { useRouter } from "next/navigation"; interface DeploymentControlsProps { deploymentId: string; currentStatus: DeploymentStatus; onStatusChange: (newStatus: DeploymentStatus) => void; } export function DeploymentControls({ deploymentId, currentStatus, onStatusChange }: DeploymentControlsProps) { const { toast } = useToast(); const router = useRouter(); const [loadingAction, setLoadingAction] = useState<"start" | "stop" | "restart" | "delete" | null>(null); const [actionToConfirm, setActionToConfirm] = useState<"start" | "stop" | "restart" | "delete" | null>(null); const [isConfirmOpen, setIsConfirmOpen] = useState(false); const handleOpenConfirmDialog = (action: "start" | "stop" | "restart" | "delete") => { setActionToConfirm(action); setIsConfirmOpen(true); }; const handleConfirmAction = async () => { if (!actionToConfirm) return; setLoadingAction(actionToConfirm); setIsConfirmOpen(false); try { let result; if (actionToConfirm === "delete") { result = await deleteDeployment(deploymentId); if (result.success) { toast({ title: "Deletion Successful", description: result.message, }); router.push('/dashboard'); // Redirect to dashboard after successful deletion } else { toast({ title: "Deletion Failed", description: result.message, variant: "destructive", }); } } else { // Handle start, stop, restart result = await controlDeployment(deploymentId, actionToConfirm as "start" | "stop" | "restart"); if (result.success) { toast({ title: "Action Successful", description: result.message, }); let newStatus: DeploymentStatus = currentStatus; if (result.newStatus) { newStatus = result.newStatus; } else { if (actionToConfirm === "start") newStatus = "deploying"; if (actionToConfirm === "stop") newStatus = "stopped"; if (actionToConfirm === "restart") newStatus = "deploying"; } onStatusChange(newStatus); } else { toast({ title: "Action Failed", description: result.message, variant: "destructive", }); } } } catch (error) { toast({ title: "Error", description: `An unexpected error occurred while performing ${actionToConfirm}.`, variant: "destructive", }); } finally { setLoadingAction(null); setActionToConfirm(null); } }; const canStart = currentStatus === 'stopped' || currentStatus === 'failed'; const canStop = currentStatus === 'succeeded' || currentStatus === 'deploying' || currentStatus === 'pending'; const canRestart = currentStatus === 'succeeded' || currentStatus === 'failed' || currentStatus === 'stopped'; // Deletion can be attempted in most states, Heroku API will handle specific restrictions if any. const getDialogTexts = () => { switch (actionToConfirm) { case "start": return { title: "Start Deployment?", description: "Are you sure you want to start this deployment? This may incur costs or use resources.", confirmText: "Yes, Start"}; case "stop": return { title: "Stop Deployment?", description: "Are you sure you want to stop this deployment? The application will become unavailable.", confirmText: "Yes, Stop", variant: "destructive" as const}; case "restart": return { title: "Restart Deployment?", description: "Are you sure you want to restart this deployment? This will stop and then start the application.", confirmText: "Yes, Restart"}; case "delete": return { title: "Delete Deployment?", description: "This action is irreversible. The Heroku app and all its data will be permanently deleted. Are you sure?", confirmText: "Yes, Delete Permanently", variant: "destructive" as const}; default: return { title: "", description: "", confirmText: ""}; } }; const dialogContent = getDialogTexts(); return ( <>