// Linux BenchTools - Devices Two-Panel Layout const { formatRelativeTime, createScoreBadge, getScoreBadgeText, escapeHtml, showError, showEmptyState, formatTags } = window.BenchUtils; const api = window.BenchAPI; let allDevices = []; let selectedDeviceId = null; // Load devices async function loadDevices() { const listContainer = document.getElementById('deviceList'); try { const data = await api.getDevices({ page_size: 1000 }); // Get all devices allDevices = data.items || []; if (allDevices.length === 0) { listContainer.innerHTML = '
📊
Aucun device
'; return; } // Sort by global_score descending allDevices.sort((a, b) => { const scoreA = a.last_benchmark?.global_score ?? -1; const scoreB = b.last_benchmark?.global_score ?? -1; return scoreB - scoreA; }); renderDeviceList(); // Auto-select first device if none selected if (!selectedDeviceId && allDevices.length > 0) { selectDevice(allDevices[0].id); } } catch (error) { console.error('Failed to load devices:', error); listContainer.innerHTML = '
❌ Erreur de chargement
'; } } // Render device list (left panel) function renderDeviceList() { const listContainer = document.getElementById('deviceList'); listContainer.innerHTML = allDevices.map(device => { const globalScore = device.last_benchmark?.global_score; const isSelected = device.id === selectedDeviceId; const scoreText = globalScore !== null && globalScore !== undefined ? Math.round(globalScore) : 'N/A'; const scoreClass = globalScore !== null && globalScore !== undefined ? window.BenchUtils.getScoreBadgeClass(globalScore) : 'badge'; return `
${escapeHtml(device.hostname)}
${scoreText}
${device.last_benchmark?.run_at ? `
⏱️ ${formatRelativeTime(device.last_benchmark.run_at)}
` : '
⚠️ Pas de benchmark
'}
`; }).join(''); } // Select device and display details async function selectDevice(deviceId) { selectedDeviceId = deviceId; renderDeviceList(); // Update selection in list const detailsContainer = document.getElementById('deviceDetailsContainer'); detailsContainer.innerHTML = '
Chargement des détails...
'; try { const device = await api.getDevice(deviceId); renderDeviceDetails(device); } catch (error) { console.error('Failed to load device details:', error); showError(detailsContainer, 'Impossible de charger les détails du device.'); } } // Render device details (right panel) function renderDeviceDetails(device) { const detailsContainer = document.getElementById('deviceDetailsContainer'); const snapshot = device.last_hardware_snapshot; const bench = device.last_benchmark; // Hardware summary const cpuModel = snapshot?.cpu_model || 'N/A'; const cpuCores = snapshot?.cpu_cores || '?'; const cpuThreads = snapshot?.cpu_threads || '?'; const ramTotalGB = Math.round((snapshot?.ram_total_mb || 0) / 1024); const ramUsedMB = snapshot?.ram_used_mb || 0; const ramFreeMB = snapshot?.ram_free_mb || 0; const ramSharedMB = snapshot?.ram_shared_mb || 0; const gpuSummary = snapshot?.gpu_summary || 'N/A'; const storage = snapshot?.storage_summary || 'N/A'; const osName = snapshot?.os_name || 'N/A'; const kernelVersion = snapshot?.kernel_version || 'N/A'; // RAM usage calculation let ramUsageHtml = `${ramTotalGB} GB`; if (ramUsedMB > 0 || ramFreeMB > 0) { const usagePercent = ramTotalGB > 0 ? Math.round((ramUsedMB / (snapshot.ram_total_mb || 1)) * 100) : 0; ramUsageHtml = ` ${ramTotalGB} GB (${usagePercent}% utilisé)
Utilisée: ${Math.round(ramUsedMB / 1024)}GB • Libre: ${Math.round(ramFreeMB / 1024)}GB${ramSharedMB > 0 ? ` • Partagée: ${Math.round(ramSharedMB / 1024)}GB` : ''} `; } // Benchmark scores const globalScore = bench?.global_score; const cpuScore = bench?.cpu_score; const memScore = bench?.memory_score; const diskScore = bench?.disk_score; const netScore = bench?.network_score; const gpuScore = bench?.gpu_score; const globalScoreHtml = globalScore !== null && globalScore !== undefined ? `${getScoreBadgeText(globalScore)}` : 'N/A'; // Network details let networkHtml = ''; if (snapshot?.network_interfaces_json) { try { const interfaces = JSON.parse(snapshot.network_interfaces_json); networkHtml = interfaces.map(iface => { const typeIcon = iface.type === 'ethernet' ? '🔌' : '📡'; const wolBadge = iface.wake_on_lan === true ? 'WoL ✓' : 'WoL ✗'; return `
${typeIcon} ${escapeHtml(iface.name)} (${iface.type})${wolBadge}
IP: ${iface.ip || 'N/A'} • MAC: ${iface.mac || 'N/A'}
Vitesse: ${iface.speed_mbps ? iface.speed_mbps + ' Mbps' : 'N/A'} ${iface.driver ? ` • Driver: ${iface.driver}` : ''}
`; }).join(''); } catch (e) { networkHtml = '

Erreur de parsing JSON

'; } } // Network benchmark results (iperf3) let netBenchHtml = ''; if (bench?.network_results_json) { try { const netResults = JSON.parse(bench.network_results_json); netBenchHtml = `
📈 Résultats Benchmark Réseau (iperf3)
↑ ${netResults.upload_mbps?.toFixed(2) || 'N/A'}
Upload Mbps
↓ ${netResults.download_mbps?.toFixed(2) || 'N/A'}
Download Mbps
${netResults.ping_ms?.toFixed(2) || 'N/A'}
Ping ms
${netResults.score?.toFixed(2) || 'N/A'}
Score
`; } catch (e) { console.error('Error parsing network results:', e); } } detailsContainer.innerHTML = `

${escapeHtml(device.hostname)}

${escapeHtml(device.description || 'Aucune description')}

${device.location ? `

📍 ${escapeHtml(device.location)}

` : ''} ${device.tags ? `
${formatTags(device.tags)}
` : ''}
${globalScoreHtml}
${bench ? `

📊 Scores de Benchmark

${createScoreCard(cpuScore, 'CPU', '🔧')} ${createScoreCard(memScore, 'Mémoire', '💾')} ${createScoreCard(diskScore, 'Disque', '💿')} ${createScoreCard(netScore, 'Réseau', '🌐')} ${createScoreCard(gpuScore, 'GPU', '🎮')}
⏱️ Dernier benchmark: ${bench.run_at ? formatRelativeTime(bench.run_at) : 'N/A'}
` : '
⚠️ Aucun benchmark disponible
'}

🖥️ Résumé Matériel

${createInfoCard('🔧 CPU', `${escapeHtml(cpuModel)}
${cpuCores} cores / ${cpuThreads} threads`)} ${createInfoCard('💾 RAM', ramUsageHtml)} ${createInfoCard('🎮 GPU', escapeHtml(gpuSummary))} ${createInfoCard('💿 Storage', escapeHtml(storage))} ${createInfoCard('🐧 OS', `${escapeHtml(osName)}
Kernel: ${escapeHtml(kernelVersion)}`)} ${createInfoCard('⏰ Créé le', new Date(device.created_at).toLocaleDateString('fr-FR'))}
${networkHtml || netBenchHtml ? `

🌐 Détails Réseau

${networkHtml} ${netBenchHtml}
` : ''}
📄 Voir la page complète
`; } // Create score card for display function createScoreCard(score, label, icon) { const scoreValue = score !== null && score !== undefined ? Math.round(score) : 'N/A'; const badgeClass = score !== null && score !== undefined ? window.BenchUtils.getScoreBadgeClass(score) : 'badge'; return `
${icon}
${label}
${scoreValue}
`; } // Create info card function createInfoCard(label, value) { return `
${label}
${value}
`; } // Initialize devices page document.addEventListener('DOMContentLoaded', () => { loadDevices(); // Refresh every 30 seconds setInterval(loadDevices, 30000); }); // Make selectDevice available globally window.selectDevice = selectDevice;