import React, { useEffect, useState, useRef, useCallback } from 'react'; import { classNames } from '~/utils/classNames'; import { Line } from 'react-chartjs-2'; import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, } from 'chart.js'; import { toast } from 'react-toastify'; // Import toast // Register ChartJS components ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend); interface BatteryManager extends EventTarget { charging: boolean; chargingTime: number; dischargingTime: number; level: number; } interface SystemMetrics { cpu: { usage: number; cores: number[]; temperature?: number; frequency?: number; }; memory: { used: number; total: number; percentage: number; heap: { used: number; total: number; limit: number; }; cache?: number; }; uptime: number; battery?: { level: number; charging: boolean; timeRemaining?: number; temperature?: number; cycles?: number; health?: number; }; network: { downlink: number; uplink?: number; latency: number; type: string; activeConnections?: number; bytesReceived: number; bytesSent: number; }; performance: { fps: number; pageLoad: number; domReady: number; resources: { total: number; size: number; loadTime: number; }; timing: { ttfb: number; fcp: number; lcp: number; }; }; storage: { total: number; used: number; free: number; type: string; }; health: { score: number; issues: string[]; suggestions: string[]; }; } interface MetricsHistory { timestamps: string[]; cpu: number[]; memory: number[]; battery: number[]; network: number[]; } interface EnergySavings { updatesReduced: number; timeInSaverMode: number; estimatedEnergySaved: number; // in mWh (milliwatt-hours) } interface PowerProfile { name: string; description: string; settings: { updateInterval: number; enableAnimations: boolean; backgroundProcessing: boolean; networkThrottling: boolean; }; } interface PerformanceAlert { type: 'warning' | 'error' | 'info'; message: string; timestamp: number; metric: string; threshold: number; value: number; } declare global { interface Navigator { getBattery(): Promise; } interface Performance { memory?: { jsHeapSizeLimit: number; totalJSHeapSize: number; usedJSHeapSize: number; }; } } const MAX_HISTORY_POINTS = 60; // 1 minute of history at 1s intervals const BATTERY_THRESHOLD = 20; // Enable energy saver when battery below 20% const UPDATE_INTERVALS = { normal: { metrics: 1000, // 1s }, energySaver: { metrics: 5000, // 5s }, }; // Energy consumption estimates (milliwatts) const ENERGY_COSTS = { update: 2, // mW per update apiCall: 5, // mW per API call rendering: 1, // mW per render }; const PERFORMANCE_THRESHOLDS = { cpu: { warning: 70, critical: 90 }, memory: { warning: 80, critical: 95 }, fps: { warning: 30, critical: 15 }, loadTime: { warning: 3000, critical: 5000 }, }; const POWER_PROFILES: PowerProfile[] = [ { name: 'Performance', description: 'Maximum performance, higher power consumption', settings: { updateInterval: 1000, enableAnimations: true, backgroundProcessing: true, networkThrottling: false, }, }, { name: 'Balanced', description: 'Balance between performance and power saving', settings: { updateInterval: 2000, enableAnimations: true, backgroundProcessing: true, networkThrottling: false, }, }, { name: 'Power Saver', description: 'Maximum power saving, reduced performance', settings: { updateInterval: 5000, enableAnimations: false, backgroundProcessing: false, networkThrottling: true, }, }, ]; export default function TaskManagerTab() { const [metrics, setMetrics] = useState({ cpu: { usage: 0, cores: [] }, memory: { used: 0, total: 0, percentage: 0, heap: { used: 0, total: 0, limit: 0 } }, uptime: 0, network: { downlink: 0, latency: 0, type: 'unknown', bytesReceived: 0, bytesSent: 0 }, performance: { fps: 0, pageLoad: 0, domReady: 0, resources: { total: 0, size: 0, loadTime: 0 }, timing: { ttfb: 0, fcp: 0, lcp: 0 }, }, storage: { total: 0, used: 0, free: 0, type: 'unknown' }, health: { score: 0, issues: [], suggestions: [] }, }); const [metricsHistory, setMetricsHistory] = useState({ timestamps: [], cpu: [], memory: [], battery: [], network: [], }); const [energySaverMode, setEnergySaverMode] = useState(() => { // Initialize from localStorage, default to false const saved = localStorage.getItem('energySaverMode'); return saved ? JSON.parse(saved) : false; }); const [autoEnergySaver, setAutoEnergySaver] = useState(() => { // Initialize from localStorage, default to false const saved = localStorage.getItem('autoEnergySaver'); return saved ? JSON.parse(saved) : false; }); const [energySavings, setEnergySavings] = useState({ updatesReduced: 0, timeInSaverMode: 0, estimatedEnergySaved: 0, }); const saverModeStartTime = useRef(null); const [selectedProfile, setSelectedProfile] = useState(POWER_PROFILES[1]); // Default to Balanced const [alerts, setAlerts] = useState([]); // Handle energy saver mode changes const handleEnergySaverChange = (checked: boolean) => { setEnergySaverMode(checked); localStorage.setItem('energySaverMode', JSON.stringify(checked)); toast.success(checked ? 'Energy Saver mode enabled' : 'Energy Saver mode disabled'); }; // Handle auto energy saver changes const handleAutoEnergySaverChange = (checked: boolean) => { setAutoEnergySaver(checked); localStorage.setItem('autoEnergySaver', JSON.stringify(checked)); toast.success(checked ? 'Auto Energy Saver enabled' : 'Auto Energy Saver disabled'); if (!checked) { // When disabling auto mode, also disable energy saver mode setEnergySaverMode(false); localStorage.setItem('energySaverMode', 'false'); } }; // Update energy savings calculation const updateEnergySavings = useCallback(() => { if (!energySaverMode) { saverModeStartTime.current = null; setEnergySavings({ updatesReduced: 0, timeInSaverMode: 0, estimatedEnergySaved: 0, }); return; } if (!saverModeStartTime.current) { saverModeStartTime.current = Date.now(); } const timeInSaverMode = Math.max(0, (Date.now() - (saverModeStartTime.current || Date.now())) / 1000); const normalUpdatesPerMinute = 60 / (UPDATE_INTERVALS.normal.metrics / 1000); const saverUpdatesPerMinute = 60 / (UPDATE_INTERVALS.energySaver.metrics / 1000); const updatesReduced = Math.floor((normalUpdatesPerMinute - saverUpdatesPerMinute) * (timeInSaverMode / 60)); const energyPerUpdate = ENERGY_COSTS.update; const energySaved = (updatesReduced * energyPerUpdate) / 3600; setEnergySavings({ updatesReduced, timeInSaverMode, estimatedEnergySaved: energySaved, }); }, [energySaverMode]); // Add interval for energy savings updates useEffect(() => { const interval = setInterval(updateEnergySavings, 1000); return () => clearInterval(interval); }, [updateEnergySavings]); // Get detailed performance metrics const getPerformanceMetrics = async (): Promise> => { try { // Get FPS const fps = await measureFrameRate(); // Get page load metrics const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming; const pageLoad = navigation.loadEventEnd - navigation.startTime; const domReady = navigation.domContentLoadedEventEnd - navigation.startTime; // Get resource metrics const resources = performance.getEntriesByType('resource'); const resourceMetrics = { total: resources.length, size: resources.reduce((total, r) => total + (r as any).transferSize || 0, 0), loadTime: Math.max(...resources.map((r) => r.duration)), }; // Get Web Vitals const ttfb = navigation.responseStart - navigation.requestStart; const paintEntries = performance.getEntriesByType('paint'); const fcp = paintEntries.find((entry) => entry.name === 'first-contentful-paint')?.startTime || 0; const lcpEntry = await getLargestContentfulPaint(); return { fps, pageLoad, domReady, resources: resourceMetrics, timing: { ttfb, fcp, lcp: lcpEntry?.startTime || 0, }, }; } catch (error) { console.error('Failed to get performance metrics:', error); return {}; } }; // Measure frame rate const measureFrameRate = async (): Promise => { return new Promise((resolve) => { const frameCount = { value: 0 }; const startTime = performance.now(); const countFrame = (time: number) => { frameCount.value++; if (time - startTime >= 1000) { resolve(Math.round((frameCount.value * 1000) / (time - startTime))); } else { requestAnimationFrame(countFrame); } }; requestAnimationFrame(countFrame); }); }; // Get Largest Contentful Paint const getLargestContentfulPaint = async (): Promise => { return new Promise((resolve) => { new PerformanceObserver((list) => { const entries = list.getEntries(); resolve(entries[entries.length - 1]); }).observe({ entryTypes: ['largest-contentful-paint'] }); // Resolve after 3 seconds if no LCP entry is found setTimeout(() => resolve(undefined), 3000); }); }; // Analyze system health const analyzeSystemHealth = (currentMetrics: SystemMetrics): SystemMetrics['health'] => { const issues: string[] = []; const suggestions: string[] = []; let score = 100; // CPU analysis if (currentMetrics.cpu.usage > PERFORMANCE_THRESHOLDS.cpu.critical) { score -= 30; issues.push('Critical CPU usage'); suggestions.push('Consider closing resource-intensive applications'); } else if (currentMetrics.cpu.usage > PERFORMANCE_THRESHOLDS.cpu.warning) { score -= 15; issues.push('High CPU usage'); suggestions.push('Monitor system processes for unusual activity'); } // Memory analysis if (currentMetrics.memory.percentage > PERFORMANCE_THRESHOLDS.memory.critical) { score -= 30; issues.push('Critical memory usage'); suggestions.push('Close unused applications to free up memory'); } else if (currentMetrics.memory.percentage > PERFORMANCE_THRESHOLDS.memory.warning) { score -= 15; issues.push('High memory usage'); suggestions.push('Consider freeing up memory by closing background applications'); } // Performance analysis if (currentMetrics.performance.fps < PERFORMANCE_THRESHOLDS.fps.critical) { score -= 20; issues.push('Very low frame rate'); suggestions.push('Disable animations or switch to power saver mode'); } else if (currentMetrics.performance.fps < PERFORMANCE_THRESHOLDS.fps.warning) { score -= 10; issues.push('Low frame rate'); suggestions.push('Consider reducing visual effects'); } // Battery analysis if (currentMetrics.battery && !currentMetrics.battery.charging && currentMetrics.battery.level < 20) { score -= 10; issues.push('Low battery'); suggestions.push('Connect to power source or enable power saver mode'); } return { score: Math.max(0, score), issues, suggestions, }; }; // Update metrics with enhanced data const updateMetrics = async () => { try { // Get memory info using Performance API const memory = performance.memory || { jsHeapSizeLimit: 0, totalJSHeapSize: 0, usedJSHeapSize: 0, }; const totalMem = memory.totalJSHeapSize / (1024 * 1024); const usedMem = memory.usedJSHeapSize / (1024 * 1024); const memPercentage = (usedMem / totalMem) * 100; // Get CPU usage using Performance API const cpuUsage = await getCPUUsage(); // Get battery info let batteryInfo: SystemMetrics['battery'] | undefined; try { const battery = await navigator.getBattery(); batteryInfo = { level: battery.level * 100, charging: battery.charging, timeRemaining: battery.charging ? battery.chargingTime : battery.dischargingTime, }; } catch { console.log('Battery API not available'); } // Get network info using Network Information API const connection = (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection; const networkInfo = { downlink: connection?.downlink || 0, uplink: connection?.uplink, latency: connection?.rtt || 0, type: connection?.type || 'unknown', activeConnections: connection?.activeConnections, bytesReceived: connection?.bytesReceived || 0, bytesSent: connection?.bytesSent || 0, }; // Get enhanced performance metrics const performanceMetrics = await getPerformanceMetrics(); const metrics: SystemMetrics = { cpu: { usage: cpuUsage, cores: [], temperature: undefined, frequency: undefined }, memory: { used: Math.round(usedMem), total: Math.round(totalMem), percentage: Math.round(memPercentage), heap: { used: Math.round(usedMem), total: Math.round(totalMem), limit: Math.round(totalMem), }, }, uptime: performance.now() / 1000, battery: batteryInfo, network: networkInfo, performance: performanceMetrics as SystemMetrics['performance'], storage: { total: 0, used: 0, free: 0, type: 'unknown', }, health: { score: 0, issues: [], suggestions: [] }, }; // Analyze system health metrics.health = analyzeSystemHealth(metrics); // Check for alerts checkPerformanceAlerts(metrics); setMetrics(metrics); // Update metrics history const now = new Date().toLocaleTimeString(); setMetricsHistory((prev) => { const timestamps = [...prev.timestamps, now].slice(-MAX_HISTORY_POINTS); const cpu = [...prev.cpu, metrics.cpu.usage].slice(-MAX_HISTORY_POINTS); const memory = [...prev.memory, metrics.memory.percentage].slice(-MAX_HISTORY_POINTS); const battery = [...prev.battery, batteryInfo?.level || 0].slice(-MAX_HISTORY_POINTS); const network = [...prev.network, networkInfo.downlink].slice(-MAX_HISTORY_POINTS); return { timestamps, cpu, memory, battery, network }; }); } catch (error) { console.error('Failed to update system metrics:', error); } }; // Get real CPU usage using Performance API const getCPUUsage = async (): Promise => { try { const t0 = performance.now(); // Create some actual work to measure and use the result let result = 0; for (let i = 0; i < 10000; i++) { result += Math.random(); } // Use result to prevent optimization if (result < 0) { console.log('Unexpected negative result'); } const t1 = performance.now(); const timeTaken = t1 - t0; /* * Normalize to percentage (0-100) * Lower time = higher CPU availability */ const maxExpectedTime = 50; // baseline in ms const cpuAvailability = Math.max(0, Math.min(100, ((maxExpectedTime - timeTaken) / maxExpectedTime) * 100)); return 100 - cpuAvailability; // Convert availability to usage } catch (error) { console.error('Failed to get CPU usage:', error); return 0; } }; // Add network change listener useEffect(() => { const connection = (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection; if (!connection) { return; } const updateNetworkInfo = () => { setMetrics((prev) => ({ ...prev, network: { downlink: connection.downlink || 0, latency: connection.rtt || 0, type: connection.type || 'unknown', bytesReceived: connection.bytesReceived || 0, bytesSent: connection.bytesSent || 0, }, })); }; connection.addEventListener('change', updateNetworkInfo); // eslint-disable-next-line consistent-return return () => connection.removeEventListener('change', updateNetworkInfo); }, []); // Remove all animation and process monitoring useEffect(() => { const metricsInterval = setInterval( () => { if (!energySaverMode) { updateMetrics(); } }, energySaverMode ? UPDATE_INTERVALS.energySaver.metrics : UPDATE_INTERVALS.normal.metrics, ); return () => { clearInterval(metricsInterval); }; }, [energySaverMode]); // Initial update effect useEffect((): (() => void) => { // Initial update updateMetrics(); // Set up intervals for live updates const metricsInterval = setInterval( updateMetrics, energySaverMode ? UPDATE_INTERVALS.energySaver.metrics : UPDATE_INTERVALS.normal.metrics, ); // Cleanup on unmount return () => { clearInterval(metricsInterval); }; }, [energySaverMode]); // Re-create intervals when energy saver mode changes const getUsageColor = (usage: number): string => { if (usage > 80) { return 'text-red-500'; } if (usage > 50) { return 'text-yellow-500'; } return 'text-gray-500'; }; const renderUsageGraph = (data: number[], label: string, color: string) => { const chartData = { labels: metricsHistory.timestamps, datasets: [ { label, data, borderColor: color, fill: false, tension: 0.4, }, ], }; const options = { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, max: 100, grid: { color: 'rgba(255, 255, 255, 0.1)', }, }, x: { grid: { display: false, }, }, }, plugins: { legend: { display: false, }, }, animation: { duration: 0, } as const, }; return (
); }; useEffect((): (() => void) | undefined => { if (!autoEnergySaver) { // If auto mode is disabled, clear any forced energy saver state setEnergySaverMode(false); return undefined; } const checkBatteryStatus = async () => { try { const battery = await navigator.getBattery(); const shouldEnableSaver = !battery.charging && battery.level * 100 <= BATTERY_THRESHOLD; setEnergySaverMode(shouldEnableSaver); } catch { console.log('Battery API not available'); } }; checkBatteryStatus(); const batteryCheckInterval = setInterval(checkBatteryStatus, 60000); return () => clearInterval(batteryCheckInterval); }, [autoEnergySaver]); // Check for performance alerts const checkPerformanceAlerts = (currentMetrics: SystemMetrics) => { const newAlerts: PerformanceAlert[] = []; // CPU alert if (currentMetrics.cpu.usage > PERFORMANCE_THRESHOLDS.cpu.critical) { newAlerts.push({ type: 'error', message: 'Critical CPU usage detected', timestamp: Date.now(), metric: 'cpu', threshold: PERFORMANCE_THRESHOLDS.cpu.critical, value: currentMetrics.cpu.usage, }); } // Memory alert if (currentMetrics.memory.percentage > PERFORMANCE_THRESHOLDS.memory.critical) { newAlerts.push({ type: 'error', message: 'Critical memory usage detected', timestamp: Date.now(), metric: 'memory', threshold: PERFORMANCE_THRESHOLDS.memory.critical, value: currentMetrics.memory.percentage, }); } // Performance alert if (currentMetrics.performance.fps < PERFORMANCE_THRESHOLDS.fps.critical) { newAlerts.push({ type: 'warning', message: 'Very low frame rate detected', timestamp: Date.now(), metric: 'fps', threshold: PERFORMANCE_THRESHOLDS.fps.critical, value: currentMetrics.performance.fps, }); } if (newAlerts.length > 0) { setAlerts((prev) => [...prev, ...newAlerts]); newAlerts.forEach((alert) => { toast.warning(alert.message); }); } }; return (
{/* Power Profile Selection */}

Power Management

handleAutoEnergySaverChange(e.target.checked)} className="form-checkbox h-4 w-4 text-purple-600 rounded border-gray-300 dark:border-gray-700" />
!autoEnergySaver && handleEnergySaverChange(e.target.checked)} disabled={autoEnergySaver} className="form-checkbox h-4 w-4 text-purple-600 rounded border-gray-300 dark:border-gray-700 disabled:opacity-50" />
{selectedProfile.description}
{/* System Health Score */}

System Health

Health Score = 80, 'text-yellow-500': metrics.health.score >= 60 && metrics.health.score < 80, 'text-red-500': metrics.health.score < 60, })} > {metrics.health.score}%
{metrics.health.issues.length > 0 && (
Issues:
    {metrics.health.issues.map((issue, index) => (
  • {issue}
  • ))}
)} {metrics.health.suggestions.length > 0 && (
Suggestions:
    {metrics.health.suggestions.map((suggestion, index) => (
  • {suggestion}
  • ))}
)}
{/* System Metrics */}

System Metrics

{/* CPU Usage */}
CPU Usage {Math.round(metrics.cpu.usage)}%
{renderUsageGraph(metricsHistory.cpu, 'CPU', '#9333ea')} {metrics.cpu.temperature && (
Temperature: {metrics.cpu.temperature}°C
)} {metrics.cpu.frequency && (
Frequency: {(metrics.cpu.frequency / 1000).toFixed(1)} GHz
)}
{/* Memory Usage */}
Memory Usage {Math.round(metrics.memory.percentage)}%
{renderUsageGraph(metricsHistory.memory, 'Memory', '#2563eb')}
Used: {formatBytes(metrics.memory.used)}
Total: {formatBytes(metrics.memory.total)}
Heap: {formatBytes(metrics.memory.heap.used)} / {formatBytes(metrics.memory.heap.total)}
{/* Performance */}
Performance = PERFORMANCE_THRESHOLDS.fps.warning, })} > {Math.round(metrics.performance.fps)} FPS
Page Load: {(metrics.performance.pageLoad / 1000).toFixed(2)}s
DOM Ready: {(metrics.performance.domReady / 1000).toFixed(2)}s
TTFB: {(metrics.performance.timing.ttfb / 1000).toFixed(2)}s
Resources: {metrics.performance.resources.total} ({formatBytes(metrics.performance.resources.size)})
{/* Network */}
Network {metrics.network.downlink.toFixed(1)} Mbps
{renderUsageGraph(metricsHistory.network, 'Network', '#f59e0b')}
Type: {metrics.network.type}
Latency: {metrics.network.latency}ms
Received: {formatBytes(metrics.network.bytesReceived)}
Sent: {formatBytes(metrics.network.bytesSent)}
{/* Battery Section */} {metrics.battery && (
Battery
{metrics.battery.charging &&
} 20 ? 'text-bolt-elements-textPrimary' : 'text-red-500', )} > {Math.round(metrics.battery.level)}%
{renderUsageGraph(metricsHistory.battery, 'Battery', '#22c55e')} {metrics.battery.timeRemaining && (
{metrics.battery.charging ? 'Time to full: ' : 'Time remaining: '} {formatTime(metrics.battery.timeRemaining)}
)} {metrics.battery.temperature && (
Temperature: {metrics.battery.temperature}°C
)} {metrics.battery.cycles && (
Charge cycles: {metrics.battery.cycles}
)} {metrics.battery.health && (
Battery health: {metrics.battery.health}%
)}
)} {/* Storage Section */}
Storage {formatBytes(metrics.storage.used)} / {formatBytes(metrics.storage.total)}
= 0.7 && metrics.storage.used / metrics.storage.total < 0.9, 'bg-red-500': metrics.storage.used / metrics.storage.total >= 0.9, })} style={{ width: `${(metrics.storage.used / metrics.storage.total) * 100}%` }} />
Free: {formatBytes(metrics.storage.free)}
Type: {metrics.storage.type}
{/* Performance Alerts */} {alerts.length > 0 && (
Recent Alerts
{alerts.slice(-5).map((alert, index) => (
{alert.message} {new Date(alert.timestamp).toLocaleTimeString()}
))}
)} {/* Energy Savings */} {energySaverMode && (

Energy Savings

Updates Reduced

{energySavings.updatesReduced}

Time in Saver Mode

{Math.floor(energySavings.timeInSaverMode / 60)}m {Math.floor(energySavings.timeInSaverMode % 60)}s

Energy Saved

{energySavings.estimatedEnergySaved.toFixed(2)} mWh

)}
); } // Helper function to format bytes const formatBytes = (bytes: number): string => { if (bytes === 0) { return '0 B'; } const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; }; // Helper function to format time const formatTime = (seconds: number): string => { if (!isFinite(seconds) || seconds === 0) { return 'Unknown'; } const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (hours > 0) { return `${hours}h ${minutes}m`; } return `${minutes}m`; };