This commit is contained in:
2025-12-14 10:40:54 +01:00
parent 5d483b0df5
commit 8428bf9c82
55 changed files with 9763 additions and 391 deletions

View File

@@ -1,20 +1,60 @@
// Linux BenchTools - Dashboard Logic
const { formatDate, formatRelativeTime, createScoreBadge, getScoreBadgeText, escapeHtml, showError, showEmptyState, copyToClipboard, showToast } = window.BenchUtils;
const { formatDate, formatRelativeTime, createScoreBadge, getScoreBadgeText, escapeHtml, showError, showEmptyState, copyToClipboard, showToast, debounce } = window.BenchUtils;
const api = window.BenchAPI;
// Global state
let allDevices = [];
let isLoading = false;
// Load dashboard data
async function loadDashboard() {
if (isLoading) return;
isLoading = true;
updateRefreshButton(true);
try {
await Promise.all([
loadStats(),
loadTopDevices()
]);
// Update last refresh time
updateLastRefreshTime();
} catch (error) {
console.error('Failed to load dashboard:', error);
showToast('Erreur lors du chargement des données', 'error');
} finally {
isLoading = false;
updateRefreshButton(false);
}
}
// Update refresh button state
function updateRefreshButton(loading) {
const btn = document.getElementById('refreshBtn');
if (!btn) return;
if (loading) {
btn.disabled = true;
btn.innerHTML = '⏳ Chargement...';
} else {
btn.disabled = false;
btn.innerHTML = '🔄 Actualiser';
}
}
// Update last refresh time
function updateLastRefreshTime() {
const element = document.getElementById('lastUpdate');
if (!element) return;
const now = new Date();
element.textContent = `Mis à jour: ${now.toLocaleTimeString('fr-FR')}`;
}
// Load statistics
async function loadStats() {
try {
@@ -72,48 +112,74 @@ async function loadTopDevices() {
if (!data.items || data.items.length === 0) {
showEmptyState(container, 'Aucun device trouvé. Exécutez un benchmark sur une machine pour commencer.', '📊');
allDevices = [];
return;
}
// Store all devices for filtering
allDevices = data.items;
// Sort by global_score descending
const sortedDevices = data.items.sort((a, b) => {
const sortedDevices = allDevices.sort((a, b) => {
const scoreA = a.last_benchmark?.global_score ?? -1;
const scoreB = b.last_benchmark?.global_score ?? -1;
return scoreB - scoreA;
});
// Generate table HTML
container.innerHTML = `
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>#</th>
<th>Hostname</th>
<th>Description</th>
<th>Score Global</th>
<th>CPU</th>
<th>MEM</th>
<th>DISK</th>
<th>NET</th>
<th>GPU</th>
<th>Dernier Bench</th>
<th>Action</th>
</tr>
</thead>
<tbody>
${sortedDevices.map((device, index) => createDeviceRow(device, index + 1)).join('')}
</tbody>
</table>
</div>
`;
// Render devices
renderDevicesTable(sortedDevices);
} catch (error) {
console.error('Failed to load devices:', error);
showError(container, 'Impossible de charger les devices. Vérifiez que le backend est accessible.');
container.innerHTML = `
<div class="error" style="text-align: center;">
<p style="margin-bottom: 1rem;">❌ Impossible de charger les devices</p>
<p style="font-size: 0.9rem; margin-bottom: 1rem;">${escapeHtml(error.message)}</p>
<button class="btn btn-primary btn-sm" onclick="loadTopDevices()">🔄 Réessayer</button>
</div>
`;
}
}
// Render devices table
function renderDevicesTable(devices) {
const container = document.getElementById('devicesTable');
if (devices.length === 0) {
container.innerHTML = `
<div style="text-align: center; padding: 2rem; color: var(--text-secondary);">
<p>Aucun device trouvé avec ces critères de recherche.</p>
</div>
`;
return;
}
container.innerHTML = `
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>#</th>
<th>Hostname</th>
<th>Description</th>
<th>Score Global</th>
<th>CPU</th>
<th>MEM</th>
<th>DISK</th>
<th>NET</th>
<th>GPU</th>
<th>Dernier Bench</th>
<th>Action</th>
</tr>
</thead>
<tbody>
${devices.map((device, index) => createDeviceRow(device, index + 1)).join('')}
</tbody>
</table>
</div>
`;
}
// Create device row HTML
function createDeviceRow(device, rank) {
const bench = device.last_benchmark;
@@ -167,13 +233,69 @@ async function copyBenchCommand() {
}
}
// Filter devices based on search query
function filterDevices(query) {
if (!query || query.trim() === '') {
renderDevicesTable(allDevices);
return;
}
const lowerQuery = query.toLowerCase();
const filtered = allDevices.filter(device => {
const hostname = (device.hostname || '').toLowerCase();
const description = (device.description || '').toLowerCase();
const location = (device.location || '').toLowerCase();
return hostname.includes(lowerQuery) ||
description.includes(lowerQuery) ||
location.includes(lowerQuery);
});
renderDevicesTable(filtered);
}
// Debounced search
const debouncedSearch = debounce((query) => {
filterDevices(query);
}, 300);
// Handle search input
function handleSearch(event) {
const query = event.target.value;
debouncedSearch(query);
}
// Clear search
function clearSearch() {
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.value = '';
filterDevices('');
}
}
// Refresh dashboard manually
function refreshDashboard() {
if (!isLoading) {
loadDashboard();
}
}
// Initialize dashboard on page load
document.addEventListener('DOMContentLoaded', () => {
loadDashboard();
// Setup search input listener
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.addEventListener('input', handleSearch);
}
// Refresh every 30 seconds
setInterval(loadDashboard, 30000);
});
// Make copyBenchCommand available globally
// Make functions available globally
window.copyBenchCommand = copyBenchCommand;
window.clearSearch = clearSearch;
window.refreshDashboard = refreshDashboard;