|
import React, { useState, useEffect } from 'react'; |
|
import { Activity, Zap, Shield, Package, Clock, TrendingUp } from 'lucide-react'; |
|
import { usePerformanceAnalyzer } from '../utils/PerformanceAnalyzer'; |
|
import { bundleOptimizer } from '../utils/BundleOptimizerAdvanced'; |
|
import { securityEnhanced } from '../utils/SecurityEnhanced'; |
|
|
|
export const PerformanceMonitor: React.FC = () => { |
|
const { getReport } = usePerformanceAnalyzer(); |
|
const [performanceData, setPerformanceData] = useState<any>(null); |
|
const [bundleData, setBundleData] = useState<any>(null); |
|
const [securityData, setSecurityData] = useState<any>(null); |
|
|
|
useEffect(() => { |
|
let mounted = true; |
|
|
|
const updateData = () => { |
|
if (!mounted) return; |
|
|
|
try { |
|
setPerformanceData(getReport()); |
|
setBundleData(bundleOptimizer.getOptimizationReport()); |
|
setSecurityData(securityEnhanced.getSecurityReport()); |
|
} catch (error) { |
|
console.warn('Erro ao atualizar dados de performance:', error); |
|
} |
|
}; |
|
|
|
updateData(); |
|
const interval = setInterval(updateData, 5000); |
|
|
|
return () => { |
|
mounted = false; |
|
clearInterval(interval); |
|
}; |
|
}, [getReport]); |
|
|
|
if (!performanceData || !bundleData || !securityData) { |
|
return ( |
|
<div className="p-6 bg-white rounded-lg shadow-lg"> |
|
<div className="animate-pulse"> |
|
<div className="h-4 bg-gray-200 rounded w-1/4 mb-4"></div> |
|
<div className="h-3 bg-gray-200 rounded w-1/2 mb-2"></div> |
|
<div className="h-3 bg-gray-200 rounded w-3/4"></div> |
|
</div> |
|
</div> |
|
); |
|
} |
|
|
|
const formatBytes = (bytes: number) => { |
|
if (bytes === 0) return '0 Bytes'; |
|
const k = 1024; |
|
const sizes = ['Bytes', 'KB', 'MB', 'GB']; |
|
const i = Math.floor(Math.log(bytes) / Math.log(k)); |
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; |
|
}; |
|
|
|
const formatMs = (ms: number) => `${ms.toFixed(1)}ms`; |
|
|
|
return ( |
|
<div className="space-y-6"> |
|
{/* Header */} |
|
<div className="bg-gradient-to-r from-blue-500 to-purple-600 text-white p-6 rounded-lg"> |
|
<h2 className="text-2xl font-bold flex items-center gap-2"> |
|
<Activity className="w-6 h-6" /> |
|
Monitor de Performance |
|
</h2> |
|
<p className="text-blue-100 mt-2"> |
|
Monitoramento em tempo real da performance, bundle e segurança |
|
</p> |
|
</div> |
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> |
|
{/* Performance Metrics */} |
|
<div className="bg-white p-6 rounded-lg shadow-lg"> |
|
<h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2"> |
|
<Zap className="w-5 h-5 text-yellow-500" /> |
|
Performance |
|
</h3> |
|
|
|
<div className="space-y-3"> |
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Tempo de Carregamento:</span> |
|
<span className="font-semibold">{formatMs(performanceData.metrics.loadTime)}</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Tempo de Renderização:</span> |
|
<span className="font-semibold">{formatMs(performanceData.metrics.renderTime)}</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Uso de Memória:</span> |
|
<span className="font-semibold">{formatBytes(performanceData.metrics.memoryUsage)}</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Requisições de Rede:</span> |
|
<span className="font-semibold">{performanceData.metrics.networkRequests}</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Taxa de Cache:</span> |
|
<span className="font-semibold text-green-600"> |
|
{performanceData.metrics.cacheHitRate.toFixed(1)}% |
|
</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
{/* Bundle Optimization */} |
|
<div className="bg-white p-6 rounded-lg shadow-lg"> |
|
<h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2"> |
|
<Package className="w-5 h-5 text-blue-500" /> |
|
Bundle |
|
</h3> |
|
|
|
<div className="space-y-3"> |
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Tamanho Original:</span> |
|
<span className="font-semibold">{formatBytes(bundleData.originalSize)}</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Tamanho Otimizado:</span> |
|
<span className="font-semibold text-green-600">{formatBytes(bundleData.optimizedSize)}</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Economia:</span> |
|
<span className="font-semibold text-green-600">{formatBytes(bundleData.savings)}</span> |
|
</div> |
|
|
|
<div className="bg-gray-200 rounded-full h-2 mt-3"> |
|
<div |
|
className="bg-green-500 h-2 rounded-full transition-all duration-300" |
|
style={{ |
|
width: `${((bundleData.savings / bundleData.originalSize) * 100).toFixed(1)}%` |
|
}} |
|
></div> |
|
</div> |
|
|
|
<p className="text-xs text-gray-600 text-center"> |
|
{((bundleData.savings / bundleData.originalSize) * 100).toFixed(1)}% de redução |
|
</p> |
|
</div> |
|
</div> |
|
|
|
{/* Security Status */} |
|
<div className="bg-white p-6 rounded-lg shadow-lg"> |
|
<h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2"> |
|
<Shield className="w-5 h-5 text-green-500" /> |
|
Segurança |
|
</h3> |
|
|
|
<div className="space-y-3"> |
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Ameaças Detectadas:</span> |
|
<span className={`font-semibold ${securityData.threatsDetected > 0 ? 'text-red-600' : 'text-green-600'}`}> |
|
{securityData.threatsDetected} |
|
</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Ameaças Mitigadas:</span> |
|
<span className="font-semibold text-green-600">{securityData.threatsMitigated}</span> |
|
</div> |
|
|
|
<div className="flex justify-between"> |
|
<span className="text-sm text-gray-600">Últimas 24h:</span> |
|
<span className="font-semibold">{securityData.recentThreats.length}</span> |
|
</div> |
|
|
|
<div className={`p-2 rounded-md text-center text-sm font-semibold ${ |
|
securityData.threatsDetected === 0 |
|
? 'bg-green-100 text-green-800' |
|
: 'bg-yellow-100 text-yellow-800' |
|
}`}> |
|
{securityData.threatsDetected === 0 ? '✅ Sistema Seguro' : '⚠️ Monitorando'} |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
{/* Recommendations */} |
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6"> |
|
{/* Performance Recommendations */} |
|
<div className="bg-white p-6 rounded-lg shadow-lg"> |
|
<h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2"> |
|
<TrendingUp className="w-5 h-5 text-green-500" /> |
|
Recomendações de Performance |
|
</h3> |
|
|
|
<div className="space-y-2"> |
|
{performanceData.recommendations.map((recommendation: string, index: number) => ( |
|
<div key={index} className="p-3 bg-gray-50 rounded-md text-sm"> |
|
{recommendation} |
|
</div> |
|
))} |
|
</div> |
|
</div> |
|
|
|
{/* Bundle Recommendations */} |
|
<div className="bg-white p-6 rounded-lg shadow-lg"> |
|
<h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2"> |
|
<Package className="w-5 h-5 text-blue-500" /> |
|
Recomendações de Bundle |
|
</h3> |
|
|
|
<div className="space-y-2"> |
|
{bundleData.recommendations.map((recommendation: string, index: number) => ( |
|
<div key={index} className="p-3 bg-gray-50 rounded-md text-sm"> |
|
{recommendation} |
|
</div> |
|
))} |
|
</div> |
|
</div> |
|
</div> |
|
|
|
{/* Component Performance */} |
|
{performanceData.components.length > 0 && ( |
|
<div className="bg-white p-6 rounded-lg shadow-lg"> |
|
<h3 className="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2"> |
|
<Clock className="w-5 h-5 text-purple-500" /> |
|
Performance de Componentes |
|
</h3> |
|
|
|
<div className="overflow-x-auto"> |
|
<table className="min-w-full table-auto"> |
|
<thead> |
|
<tr className="bg-gray-50"> |
|
<th className="px-4 py-2 text-left text-sm font-semibold text-gray-600">Componente</th> |
|
<th className="px-4 py-2 text-left text-sm font-semibold text-gray-600">Renders</th> |
|
<th className="px-4 py-2 text-left text-sm font-semibold text-gray-600">Tempo Total</th> |
|
<th className="px-4 py-2 text-left text-sm font-semibold text-gray-600">Tempo Médio</th> |
|
<th className="px-4 py-2 text-left text-sm font-semibold text-gray-600">Status</th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
{performanceData.components.slice(0, 10).map((component: any, index: number) => { |
|
const avgTime = component.renderTime / component.renderCount; |
|
const status = avgTime > 16 ? 'slow' : avgTime > 8 ? 'medium' : 'fast'; |
|
|
|
return ( |
|
<tr key={index} className="border-t"> |
|
<td className="px-4 py-2 text-sm text-gray-800">{component.name}</td> |
|
<td className="px-4 py-2 text-sm text-gray-600">{component.renderCount}</td> |
|
<td className="px-4 py-2 text-sm text-gray-600">{formatMs(component.renderTime)}</td> |
|
<td className="px-4 py-2 text-sm text-gray-600">{formatMs(avgTime)}</td> |
|
<td className="px-4 py-2"> |
|
<span className={`px-2 py-1 rounded-full text-xs font-semibold ${ |
|
status === 'fast' ? 'bg-green-100 text-green-800' : |
|
status === 'medium' ? 'bg-yellow-100 text-yellow-800' : |
|
'bg-red-100 text-red-800' |
|
}`}> |
|
{status === 'fast' ? '🚀 Rápido' : |
|
status === 'medium' ? '⚡ Médio' : '🐌 Lento'} |
|
</span> |
|
</td> |
|
</tr> |
|
); |
|
})} |
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
)} |
|
</div> |
|
); |
|
}; |
|
|
|
export default PerformanceMonitor; |
|
|