// Linux BenchTools - Utility Functions // Format date to readable string function formatDate(dateString) { if (!dateString) return 'N/A'; const date = new Date(dateString); return date.toLocaleString('fr-FR', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } // Format date to relative time function formatRelativeTime(dateString) { if (!dateString) return 'N/A'; const date = new Date(dateString); const now = new Date(); const diff = now - date; const seconds = Math.floor(diff / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (days > 0) return `il y a ${days} jour${days > 1 ? 's' : ''}`; if (hours > 0) return `il y a ${hours} heure${hours > 1 ? 's' : ''}`; if (minutes > 0) return `il y a ${minutes} minute${minutes > 1 ? 's' : ''}`; return `il y a ${seconds} seconde${seconds > 1 ? 's' : ''}`; } // Format file size function formatFileSize(bytes) { if (!bytes || bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i]; } // Get score badge class based on value function getScoreBadgeClass(score) { if (score === null || score === undefined) return 'score-badge'; if (score >= 76) return 'score-badge score-high'; if (score >= 51) return 'score-badge score-medium'; return 'score-badge score-low'; } // Get score badge text function getScoreBadgeText(score) { if (score === null || score === undefined) return '--'; return Math.round(score); } // Create score badge HTML function createScoreBadge(score, label = '') { const badgeClass = getScoreBadgeClass(score); const scoreText = getScoreBadgeText(score); const labelHtml = label ? `
${label}
` : ''; return `
${labelHtml}
${scoreText}
`; } // Escape HTML to prevent XSS function escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Copy text to clipboard async function copyToClipboard(text) { try { await navigator.clipboard.writeText(text); return true; } catch (err) { console.error('Failed to copy:', err); // Fallback for older browsers const textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.left = '-999999px'; document.body.appendChild(textArea); textArea.select(); try { document.execCommand('copy'); document.body.removeChild(textArea); return true; } catch (err) { document.body.removeChild(textArea); return false; } } } // Show toast notification function showToast(message, type = 'info') { // Remove existing toasts const existingToast = document.querySelector('.toast'); if (existingToast) { existingToast.remove(); } const toast = document.createElement('div'); toast.className = `toast toast-${type}`; toast.style.cssText = ` position: fixed; top: 20px; right: 20px; padding: 1rem 1.5rem; background-color: var(--bg-secondary); border-left: 4px solid var(--color-${type === 'success' ? 'success' : type === 'error' ? 'danger' : 'info'}); border-radius: var(--radius-sm); color: var(--text-primary); z-index: 10000; animation: slideIn 0.3s ease-out; `; toast.textContent = message; document.body.appendChild(toast); setTimeout(() => { toast.style.animation = 'slideOut 0.3s ease-out'; setTimeout(() => toast.remove(), 300); }, 3000); } // Add CSS animations for toast const style = document.createElement('style'); style.textContent = ` @keyframes slideIn { from { transform: translateX(400px); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(400px); opacity: 0; } } `; document.head.appendChild(style); // Debounce function for search inputs function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Parse tags from string function parseTags(tagsString) { if (!tagsString) return []; if (Array.isArray(tagsString)) return tagsString; try { // Try to parse as JSON return JSON.parse(tagsString); } catch { // Fall back to comma-separated return tagsString.split(',').map(tag => tag.trim()).filter(tag => tag); } } // Format tags as HTML function formatTags(tagsString) { const tags = parseTags(tagsString); if (tags.length === 0) return 'Aucun tag'; return tags.map(tag => `${escapeHtml(tag)}` ).join(''); } // Get URL parameter function getUrlParameter(name) { const params = new URLSearchParams(window.location.search); return params.get(name); } // Set URL parameter without reload function setUrlParameter(name, value) { const url = new URL(window.location); url.searchParams.set(name, value); window.history.pushState({}, '', url); } // Loading state management function showLoading(element) { if (!element) return; element.innerHTML = '
Chargement
'; } function hideLoading(element) { if (!element) return; const loading = element.querySelector('.loading'); if (loading) loading.remove(); } // Error display function showError(element, message) { if (!element) return; element.innerHTML = `
Erreur: ${escapeHtml(message)}
`; } // Empty state display function showEmptyState(element, message, icon = '📭') { if (!element) return; element.innerHTML = `
${icon}

${escapeHtml(message)}

`; } // Format hardware info for display function formatHardwareInfo(snapshot) { if (!snapshot) return {}; return { cpu: `${snapshot.cpu_model || 'N/A'} (${snapshot.cpu_cores || 0}C/${snapshot.cpu_threads || 0}T)`, ram: `${Math.round((snapshot.ram_total_mb || 0) / 1024)} GB`, gpu: snapshot.gpu_summary || snapshot.gpu_model || 'N/A', storage: snapshot.storage_summary || 'N/A', os: `${snapshot.os_name || 'N/A'} ${snapshot.os_version || ''}`, kernel: snapshot.kernel_version || 'N/A' }; } // Tab management function initTabs(containerSelector) { const container = document.querySelector(containerSelector); if (!container) return; const tabs = container.querySelectorAll('.tab'); const contents = container.querySelectorAll('.tab-content'); tabs.forEach(tab => { tab.addEventListener('click', () => { // Remove active class from all tabs and contents tabs.forEach(t => t.classList.remove('active')); contents.forEach(c => c.classList.remove('active')); // Add active class to clicked tab tab.classList.add('active'); // Show corresponding content const targetId = tab.dataset.tab; const targetContent = container.querySelector(`#${targetId}`); if (targetContent) { targetContent.classList.add('active'); } }); }); } // Modal management function openModal(modalId) { const modal = document.getElementById(modalId); if (modal) { modal.classList.add('active'); } } function closeModal(modalId) { const modal = document.getElementById(modalId); if (modal) { modal.classList.remove('active'); } } // Initialize modal close buttons document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.modal').forEach(modal => { modal.addEventListener('click', (e) => { if (e.target === modal) { modal.classList.remove('active'); } }); const closeBtn = modal.querySelector('.modal-close'); if (closeBtn) { closeBtn.addEventListener('click', () => { modal.classList.remove('active'); }); } }); }); // Export functions for use in other files window.BenchUtils = { formatDate, formatRelativeTime, formatFileSize, getScoreBadgeClass, getScoreBadgeText, createScoreBadge, escapeHtml, copyToClipboard, showToast, debounce, parseTags, formatTags, getUrlParameter, setUrlParameter, showLoading, hideLoading, showError, showEmptyState, formatHardwareInfo, initTabs, openModal, closeModal };