import React, { useState } from 'react'; import { AlertCircle, Clock, Database, FileX, Loader2, CheckCircle2, Hash, Copy, Download, Check } from 'lucide-react'; const MAX_DISPLAY_ROWS = 1000; export default function ResultTable({ result, loading, pollingProgress }) { const [copied, setCopied] = useState(false); // Normalize data let columns = []; let rows = []; if (result && !result.error) { if (result.rows && result.columns) { columns = result.columns; rows = result.rows; } else if (Array.isArray(result.data) && result.data.length > 0) { columns = Object.keys(result.data[0]); rows = result.data; } else if (Array.isArray(result) && result.length > 0) { columns = Object.keys(result[0]); rows = result; } } // Function to convert data to CSV const generateCSV = (cols, dataRows) => { const header = cols.join(','); const csvRows = dataRows.map(row => { return cols.map(col => { let val = Array.isArray(row) ? row[cols.indexOf(col)] : row[col]; if (val === null || val === undefined) val = ''; val = String(val).replace(/"/g, '""'); if (val.includes(',') || val.includes('"') || val.includes('\n')) { val = `"${val}"`; } return val; }).join(','); }); return [header, ...csvRows].join('\n'); }; // Download as CSV const handleDownloadCSV = (cols, dataRows) => { const csv = generateCSV(cols, dataRows); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', `query_result_${Date.now()}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); }; // Auto-download if too many rows React.useEffect(() => { if (rows.length > MAX_DISPLAY_ROWS) { handleDownloadCSV(columns, rows); } }, [result]); // Copy to clipboard const handleCopy = (cols, dataRows) => { const csv = generateCSV(cols, dataRows); navigator.clipboard.writeText(csv).then(() => { setCopied(true); setTimeout(() => setCopied(false), 2000); }); }; // Loading state if (loading) { return (
{pollingProgress ? 'Esperando respuesta del agente remoto...' : 'Enviando comando...'}
{pollingProgress && (Polling: {pollingProgress.attempts} / {pollingProgress.maxAttempts}
Los resultados aparecerán aquí
{result.error}
{result.command_id && (
Command ID: #{result.command_id}
)}El archivo se encuentra disponible en el servidor FTP especificado.
La consulta no devolvió resultados.
Para mantener el rendimiento del navegador, los resultados que superan las {MAX_DISPLAY_ROWS} filas no se muestran en pantalla y se descargan automáticamente como CSV.
{result.command_id && (Command ID: #{result.command_id}
)}| # | {columns.map((col, idx) => ({col} | ))}
|---|---|
| {rIdx + 1} | {columns.map((col, cIdx) => { let val; if (Array.isArray(row)) { val = row[cIdx]; } else { val = row[col]; } return ({val === null ? ( NULL ) : typeof val === 'object' ? ( {JSON.stringify(val)} ) : ( String(val) )} | ); })}