'use client'; import { useState, useEffect } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Progress } from '@/components/ui/progress'; import { CheckCircle2, XCircle, Loader2, Download, RefreshCw, AlertCircle, ExternalLink, Settings, Wrench, Server, Cpu, HardDrive, MemoryStick, Shield, Zap, Terminal } from 'lucide-react'; import { invoke } from '@tauri-apps/api/core'; import { listen } from '@tauri-apps/api/event'; import { useToast } from '@/hooks/use-toast'; import { SearxngInstallWizard } from './searxng-install-wizard'; import { DockerCommandsModal } from './docker-commands-modal'; import { findProblemSolution, ProblemSolution } from '@/lib/docker-problems'; import { cn } from '@/lib/utils'; interface SystemRequirements { status: 'pass' | 'fail' | 'warn'; os: string; arch: string; ram_mb: number; disk_gb: number; cpu_cores: number; kernel_version?: string; issues: string[]; warnings: string[]; } interface InstallProgressEvent { event_type: 'step_start' | 'log' | 'step_complete' | 'error' | 'complete'; step?: number; step_name?: string; total_steps?: number; progress: number; message?: string; log_line?: string; } interface FixProgressEvent { event_type: 'start' | 'progress' | 'complete' | 'error'; message: string; progress?: number; } interface ValidationResult { status: 'pass' | 'fail' | 'partial'; tests: Array<{ name: string; status: 'pass' | 'fail' | 'warn'; message?: string; }>; docker_version?: string; } export function DockerSettingsPanel() { const { toast } = useToast(); const [dockerAvailable, setDockerAvailable] = useState(null); const [dockerRunning, setDockerRunning] = useState(null); const [isChecking, setIsChecking] = useState(false); const [requirements, setRequirements] = useState(null); const [isCheckingRequirements, setIsCheckingRequirements] = useState(false); const [isInstallingDocker, setIsInstallingDocker] = useState(false); const [isFixing, setIsFixing] = useState(false); const [fixProgress, setFixProgress] = useState<{ message: string; progress: number } | null>(null); const [dockerInstallProgress, setDockerInstallProgress] = useState<{ currentStep: number; totalSteps: number; progress: number; currentStepName: string; logs: string[]; }>({ currentStep: 0, totalSteps: 0, progress: 0, currentStepName: '', logs: [], }); const [validationResult, setValidationResult] = useState(null); const [isValidating, setIsValidating] = useState(false); const [showInstallWizard, setShowInstallWizard] = useState(false); const [showCommandsModal, setShowCommandsModal] = useState(false); const [selectedProblem, setSelectedProblem] = useState(null); // Verificar Docker ao montar useEffect(() => { checkDocker(); checkRequirements(); }, []); // Listener de eventos de progresso Docker useEffect(() => { let unlistenPromise: Promise<() => void> | null = null; if (isInstallingDocker) { unlistenPromise = listen('docker-install-progress', (event) => { const data = event.payload; switch (data.event_type) { case 'step_start': setDockerInstallProgress(prev => ({ ...prev, currentStep: data.step || 0, totalSteps: data.total_steps || prev.totalSteps, currentStepName: data.step_name || '', progress: data.progress, })); if (data.message) { setDockerInstallProgress(prev => ({ ...prev, logs: [...prev.logs.slice(-49), data.message!], })); } break; case 'log': if (data.log_line) { setDockerInstallProgress(prev => ({ ...prev, logs: [...prev.logs.slice(-49), data.log_line!], })); } break; case 'step_complete': setDockerInstallProgress(prev => ({ ...prev, progress: data.progress, })); if (data.message) { setDockerInstallProgress(prev => ({ ...prev, logs: [...prev.logs.slice(-49), data.message!], })); } break; case 'error': toast({ title: 'Erro na instalação', description: data.message || 'Erro desconhecido', variant: 'destructive', }); setIsInstallingDocker(false); break; case 'complete': setDockerInstallProgress(prev => ({ ...prev, progress: 100 })); setIsInstallingDocker(false); toast({ title: 'Docker instalado', description: 'Docker foi instalado com sucesso!', }); setTimeout(() => { validateDocker(); checkDocker(); }, 1000); break; } }); } return () => { if (unlistenPromise) { unlistenPromise.then(fn => fn()); } }; }, [isInstallingDocker, toast]); // Listener de eventos de correção useEffect(() => { let unlistenPromise: Promise<() => void> | null = null; if (isFixing) { unlistenPromise = listen('docker-fix-progress', (event) => { const data = event.payload; switch (data.event_type) { case 'start': setFixProgress({ message: data.message, progress: 0 }); break; case 'progress': setFixProgress({ message: data.message, progress: data.progress || 0 }); break; case 'complete': setFixProgress({ message: data.message, progress: 100 }); setTimeout(() => { setIsFixing(false); setFixProgress(null); checkRequirements(); toast({ title: 'Correção concluída', description: data.message, }); }, 1500); break; case 'error': setIsFixing(false); setFixProgress(null); toast({ title: 'Erro na correção', description: data.message, variant: 'destructive', }); break; } }); } return () => { if (unlistenPromise) { unlistenPromise.then(fn => fn()); } }; }, [isFixing, toast]); const checkDocker = async () => { setIsChecking(true); try { const available = await invoke('check_docker_available'); setDockerAvailable(available); if (available) { const running = await invoke('check_docker_running'); setDockerRunning(running); } else { setDockerRunning(false); } } catch (error) { console.error('Error checking Docker:', error); setDockerAvailable(false); setDockerRunning(false); } finally { setIsChecking(false); } }; const checkRequirements = async () => { setIsCheckingRequirements(true); try { const reqs = await invoke('check_docker_requirements'); setRequirements(reqs); } catch (error) { console.error('Error checking requirements:', error); setRequirements({ status: 'fail', os: 'unknown', arch: 'unknown', ram_mb: 0, disk_gb: 0, cpu_cores: 0, issues: ['Erro ao verificar requisitos do sistema'], warnings: [], }); } finally { setIsCheckingRequirements(false); } }; const handleFixRequirements = async () => { if (!requirements || requirements.issues.length === 0) { toast({ title: 'Nada para corrigir', description: 'Não há problemas encontrados que possam ser corrigidos automaticamente', }); return; } setIsFixing(true); setFixProgress({ message: 'Preparando correção...', progress: 0 }); try { await invoke('fix_docker_requirements', { os: requirements.os, issues: requirements.issues, }); } catch (error) { console.error('Error fixing requirements:', error); setIsFixing(false); setFixProgress(null); toast({ title: 'Erro na correção', description: error instanceof Error ? error.message : 'Erro desconhecido', variant: 'destructive', }); } }; const handleInstallDocker = async () => { setIsInstallingDocker(true); setDockerInstallProgress({ currentStep: 0, totalSteps: 0, progress: 0, currentStepName: '', logs: [], }); try { await invoke('install_docker'); } catch (error) { console.error('Docker installation error:', error); toast({ title: 'Erro na instalação', description: error instanceof Error ? error.message : 'Erro desconhecido durante instalação do Docker', variant: 'destructive', }); setIsInstallingDocker(false); } }; const validateDocker = async () => { setIsValidating(true); setValidationResult(null); try { const result = await invoke('validate_docker_installation'); setValidationResult(result); if (result.status === 'pass' || result.status === 'partial') { setDockerAvailable(true); setDockerRunning(true); toast({ title: 'Docker validado', description: 'Docker está funcionando corretamente', }); } else { toast({ title: 'Validação falhou', description: 'Alguns testes de validação falharam', variant: 'destructive', }); } } catch (error) { console.error('Validation error:', error); toast({ title: 'Erro na validação', description: error instanceof Error ? error.message : 'Erro ao validar Docker', variant: 'destructive', }); } finally { setIsValidating(false); } }; const getStatusIcon = (status: 'pass' | 'fail' | 'warn') => { switch (status) { case 'pass': return ; case 'fail': return ; case 'warn': return ; } }; return (
{/* Status do Docker */}
Status do Docker
Verifique se Docker está instalado e rodando
{isChecking ? (
Verificando...
) : ( <>
Instalação {dockerAvailable ? ( ) : ( )}
{dockerAvailable ? 'Instalado' : 'Não Instalado'}
Serviço {dockerRunning ? ( ) : ( )}
{dockerRunning ? 'Rodando' : 'Parado'}
{dockerAvailable === false && ( Docker não está instalado. Instale-o para usar SearXNG. )} {dockerAvailable && !dockerRunning && ( Docker está instalado mas não está rodando. Inicie o Docker Desktop. )} )}
{/* Requisitos do Sistema */}
Requisitos do Sistema
{requirements && requirements.issues.length > 0 && ( )}
Verifique se seu sistema atende aos requisitos para Docker
{isCheckingRequirements ? (
Verificando requisitos...
) : requirements ? ( <> {/* Status Geral */}
{getStatusIcon(requirements.status)}

Status Geral

{requirements.status === 'pass' && 'Sistema compatível'} {requirements.status === 'warn' && 'Avisos encontrados'} {requirements.status === 'fail' && 'Problemas encontrados'}

{requirements.status === 'pass' && 'Compatível'} {requirements.status === 'warn' && 'Avisos'} {requirements.status === 'fail' && 'Incompatível'}
{/* Especificações do Sistema */}
RAM

{(requirements.ram_mb / 1024).toFixed(1)} GB

Disco Livre

{requirements.disk_gb} GB

CPU Cores

{requirements.cpu_cores}

Sistema

{requirements.os} ({requirements.arch})

{/* Progresso de Correção */} {isFixing && fixProgress && (
{fixProgress.message} {fixProgress.progress}%
)} {/* Problemas */} {requirements.issues.length > 0 && (

Problemas Encontrados:

    {requirements.issues.map((issue, idx) => { const solution = findProblemSolution(issue, requirements.os); return (
  • {issue} {solution && (
    {solution.commands && solution.commands.length > 0 && ( )} {solution.links.length > 0 && ( )}
    )}
  • ); })}
)} {/* Avisos */} {requirements.warnings.length > 0 && (

Avisos:

    {requirements.warnings.map((warning, idx) => { const solution = findProblemSolution(warning, requirements.os); return (
  • {warning} {solution && (
    {solution.commands && solution.commands.length > 0 && ( )} {solution.links.length > 0 && ( )}
    )}
  • ); })}
)} ) : null}
{/* Instalação Docker */} {dockerAvailable === false && (
Instalar Docker
Instale Docker automaticamente ou manualmente
{isInstallingDocker && (
{dockerInstallProgress.currentStepName || 'Instalando Docker...'} {dockerInstallProgress.progress}%
{dockerInstallProgress.logs.length > 0 && (
{dockerInstallProgress.logs.map((log, idx) => (
{log}
))}
)}
)}
)} {/* Validação */} {dockerAvailable && (
Validação
Execute testes para verificar se Docker está funcionando corretamente
{validationResult ? (
{validationResult.tests.map((test, idx) => (

{test.name}

{test.message && (

{test.message}

)}
{test.status === 'pass' ? ( ) : test.status === 'warn' ? ( ) : ( )}
))} {validationResult.docker_version && (

Docker {validationResult.docker_version} instalado

)}
) : (

Clique em "Validar" para executar os testes

)}
)} {/* Botão para configurar SearXNG */} {dockerAvailable && dockerRunning && ( )} {showInstallWizard && ( { setShowInstallWizard(false); checkDocker(); toast({ title: 'SearXNG configurado', description: 'SearXNG foi instalado e configurado com sucesso!', }); }} onCancel={() => setShowInstallWizard(false)} initialUrl="http://localhost:8080" /> )}
); }