'use client'; import { useEffect, useRef, useState } from 'react'; import { listen } from '@tauri-apps/api/event'; import { Progress } from '@/components/ui/progress'; interface LogLine { line: string; type: 'stdout' | 'stderr'; progress?: number; } interface InstallationTerminalProps { onComplete?: () => void; onError?: (error: string) => void; } export function InstallationTerminal({ onComplete, onError }: InstallationTerminalProps) { const [logs, setLogs] = useState([]); const [progress, setProgress] = useState(0); const scrollRef = useRef(null); const lastProgressRef = useRef(0); // Auto-scroll para última linha useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [logs]); // Escutar eventos de log useEffect(() => { const unlistenPromise = listen('install-log', (event) => { const logLine = event.payload; setLogs(prev => [...prev, logLine]); // Atualizar progresso se disponível if (logLine.progress !== undefined) { setProgress(logLine.progress); lastProgressRef.current = logLine.progress; } else { // Tentar extrair progresso da linha de texto const extractedProgress = extractProgressFromText(logLine.line); if (extractedProgress !== null) { setProgress(extractedProgress); lastProgressRef.current = extractedProgress; } } // Verificar se instalação foi concluída const lineLower = logLine.line.toLowerCase(); if (lineLower.includes('success') || lineLower.includes('completed') || lineLower.includes('finished')) { setProgress(100); if (onComplete) { setTimeout(() => onComplete(), 500); } } // Verificar se houve erro if (logLine.type === 'stderr' && (lineLower.includes('error') || lineLower.includes('failed'))) { if (onError) { onError(logLine.line); } } }); return () => { unlistenPromise.then(unlisten => unlisten()); }; }, [onComplete, onError]); return (
Terminal
{progress > 0 && ( {progress}% )}
{logs.length === 0 ? (
Aguardando logs...
) : ( logs.map((log, index) => (
{log.line}
)) )}
{progress > 0 && (
{progress < 100 ? `Instalando... ${progress}%` : 'Instalação concluída'}
)}
); } /// Extrai progresso percentual de uma linha de texto function extractProgressFromText(line: string): number | null { // Procurar por padrão "Progress: n%" ou "n%" const percentMatch = line.match(/(\d+)%/); if (percentMatch) { const num = parseInt(percentMatch[1], 10); if (num >= 0 && num <= 100) { return num; } } // Mapear keywords para progresso aproximado const lineLower = line.toLowerCase(); if (lineLower.includes('downloading')) { return 25; } else if (lineLower.includes('installing')) { return 50; } else if (lineLower.includes('shim') || lineLower.includes('creating')) { return 75; } else if (lineLower.includes('finished') || lineLower.includes('completed') || lineLower.includes('success')) { return 100; } return null; }