"use client"; import { useState, useEffect, useRef } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Database, Loader2, RefreshCw, Trash2, AlertTriangle, CheckCircle2, XCircle, Terminal } from "lucide-react"; import { getSeederApiUrl } from "@/lib/config"; import { toast } from "sonner"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { ScrollArea } from "@/components/ui/scroll-area"; import { cn } from "@/lib/utils"; export default function SeederPage() { const [isSeeding, setIsSeeding] = useState(false); const [isResetting, setIsResetting] = useState(false); // Log Dialog State const [showLogDialog, setShowLogDialog] = useState(false); const [logs, setLogs] = useState([]); const [processStatus, setProcessStatus] = useState<'idle' | 'running' | 'success' | 'error'>('idle'); const scrollEndRef = useRef(null); const [showConfirmDialog, setShowConfirmDialog] = useState(false); // Auto-scroll to bottom of logs useEffect(() => { if (scrollEndRef.current) { scrollEndRef.current.scrollIntoView({ behavior: "smooth" }); } }, [logs]); const handleStream = async (endpoint: string, type: 'seed' | 'reset') => { setLogs([]); setProcessStatus('running'); setShowLogDialog(true); if (type === 'seed') setIsSeeding(true); else setIsResetting(true); try { // For now, only /seed supports streaming in the backend v2 we implemented // Check if backend supports stream. if not fallback? // We implemented /seed/stream in server.js today. // But /reset might not support it yet unless updated. // Let's assume /reset is still legacy POST for now, or update it later. // Actually, for consistency, let's keep /reset as POST but show a simple loader, // or better, implement /reset/stream too? // The user asked for "log popup" primarily for seeding content. if (type === 'reset') { // Legacy Reset (POST) - Mimic stream output setLogs(['🚀 Starting flush/reset process...']); const res = await fetch(`${getSeederApiUrl()}/reset`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, // Fix for Express parsing empty body if needed body: JSON.stringify({}) // Explicit empty body }); const data = await res.json(); if (res.ok) { setLogs(prev => [...prev, '✅ Reset completed successfully!', JSON.stringify(data, null, 2)]); setProcessStatus('success'); toast.success("Banco resetado com sucesso!"); } else { setLogs(prev => [...prev, '❌ Reset failed.', data.message]); setProcessStatus('error'); toast.error("Erro ao resetar"); } return; } // Real Streaming for Seed const eventSource = new EventSource(`${getSeederApiUrl()}/seed/stream?type=full`); eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.message) { setLogs(prev => [...prev, data.message]); } if (data.type === 'done') { setProcessStatus('success'); eventSource.close(); toast.success("Processo concluído!"); } else if (data.type === 'error') { setProcessStatus('error'); setLogs(prev => [...prev, `❌ Error: ${data.error}`]); eventSource.close(); toast.error("Processo falhou"); } } catch (e) { console.error("Parse error", e); } }; eventSource.onerror = (err) => { // Determine if it was a connection error or just closed if (processStatus !== 'success') { // setLogs(prev => [...prev, '⚠️ Connection closed or error.']); // Often EventSource reconnects, so we don't assume fatal error immediately unless closed manually // But for this one-shot script, we usually close on success. // If we get error before success, it's an issue. // Let's rely on the explicit 'done'/'error' messages. eventSource.close(); } }; } catch (error) { console.error(error); setProcessStatus('error'); setLogs(prev => [...prev, String(error)]); } finally { if (type === 'reset') { setIsResetting(false); } // setIsSeeding is cleared when dialog closes or execution finishes } }; const closeDialog = () => { if (processStatus === 'running') return; // Prevent closing while running? Or allow background? setShowLogDialog(false); setIsSeeding(false); setIsResetting(false); }; return (

🌱 Seeder & Reset

Gerencie o estado do banco de dados de desenvolvimento

{/* Seed Card */} Popular Banco de Dados Injeta dados massivos para teste e desenvolvimento

O que será criado:

  • Empresas (ACME, Stark, fake generates)
  • Usuários (Recruiters, Candidates, Admins)
  • Vagas de emprego e Candidaturas
  • Cidades, Estados e Países
  • Tickets e Notificações
{/* Reset Card */} Resetar / Limpar Banco Ação destrutiva para limpar o ambiente

O que será apagado:

  • Todas as empresas e vagas
  • Todos os usuários (exceto SuperAdmin)
  • Candidaturas e históricos
  • Logs e notificações
{/* Log Dialog */} { if (!open && processStatus !== 'running') closeDialog(); }}> {processStatus === 'running' && } {processStatus === 'success' && } {processStatus === 'error' && } Console de execução Acompanhe o progresso da operação em tempo real. {/* Terminal Window */}
{/* Terminal Header */}
root@gohorse-seeder:~# script.sh
{/* Scrollable Logs */}
{logs.length === 0 && processStatus === 'idle' && (
Aguardando início...
)} {logs.map((log, i) => (
{new Date().toLocaleTimeString()} {log.includes('❌') ? ( {log} ) : log.includes('✅') ? ( {log} ) : log.includes('🚀') ? ( {log} ) : ( {log} )}
))}
Status: {processStatus}
{/* Confirmation Dialog */} Atenção Absoluta! Você está prestes a APAGAR TODOS OS DADOS do banco de dados (exceto admin).

Esta ação é irreversível. Todas as vagas, candidaturas e empresas serão perdidas.
); }