// Dashboard JavaScript // Format numbers function formatNumber(num) { if (num >= 1000000000) return (num / 1000000000).toFixed(2) + 'B'; if (num >= 1000000) return (num / 1000000).toFixed(2) + 'M'; if (num >= 1000) return (num / 1000).toFixed(2) + 'K'; return num.toString(); } // Format difficulty (always with M suffix and 1 decimal) function formatDifficulty(num) { if (num >= 1000000000) return (num / 1000000000).toFixed(1) + ' B'; if (num >= 1000000) return (num / 1000000).toFixed(1) + ' M'; if (num >= 1000) return (num / 1000).toFixed(1) + ' K'; return num.toFixed(1); } // Format block height (always full integer with thousands separator) function formatBlockHeight(num) { return num.toLocaleString('en-US'); } // Format bytes function formatBytes(bytes) { 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]; } // Format time function formatTime(timestamp) { const date = new Date(timestamp * 1000); return date.toLocaleTimeString(); } // Format duration function formatDuration(seconds) { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (days > 0) return `${days}d ${hours}h`; if (hours > 0) return `${hours}h ${minutes}m`; return `${minutes}m`; } // Update health status function updateHealthStatus(data) { const statusEl = document.getElementById('healthStatus'); const statusDot = statusEl.querySelector('.status-dot'); const statusText = statusEl.querySelector('.status-text'); if (data.status === 'healthy') { statusEl.classList.remove('degraded'); statusText.textContent = 'All Systems Operational'; } else { statusEl.classList.add('degraded'); statusText.textContent = 'Service Degraded'; } } // Update system resources async function updateSystemResources() { try { const response = await fetch('/api/system/resources'); const data = await response.json(); if (data.error) { console.error('System resources error:', data.error); return; } // Update CPU const cpuPercent = data.cpu.percent.toFixed(1); document.getElementById('cpuValue').textContent = cpuPercent + '%'; document.getElementById('cpuProgress').style.width = cpuPercent + '%'; // Update Memory const memPercent = data.memory.percent.toFixed(1); document.getElementById('memoryValue').textContent = memPercent + '%'; document.getElementById('memoryProgress').style.width = memPercent + '%'; // Update Disk const diskPercent = data.disk.percent.toFixed(1); document.getElementById('diskValue').textContent = diskPercent + '%'; document.getElementById('diskProgress').style.width = diskPercent + '%'; } catch (error) { console.error('Error fetching system resources:', error); } } // Update Palladium info async function updatePalladiumInfo() { try { const response = await fetch('/api/palladium/info'); const data = await response.json(); if (data.error) { console.error('Palladium info error:', data.error); return; } // Update blockchain info if (data.blockchain) { document.getElementById('blockHeight').textContent = formatBlockHeight(data.blockchain.blocks || 0); document.getElementById('difficulty').textContent = formatDifficulty(data.blockchain.difficulty || 0); document.getElementById('network').textContent = (data.blockchain.chain || 'unknown').toUpperCase(); const progress = ((data.blockchain.verificationprogress || 0) * 100).toFixed(2); document.getElementById('syncProgress').textContent = progress + '%'; } // Update network info if (data.network) { let version = data.network.subversion || 'Unknown'; // Extract version number from /Palladium:2.0.0/ format const match = version.match(/:([\d.]+)/); if (match) { version = 'v' + match[1]; } document.getElementById('nodeVersion').textContent = version; } // Update connections document.getElementById('connections').textContent = data.peers || 0; // Update mempool info if (data.mempool) { document.getElementById('mempoolSize').textContent = data.mempool.size || 0; document.getElementById('mempoolBytes').textContent = formatBytes(data.mempool.bytes || 0); document.getElementById('mempoolMax').textContent = formatBytes(data.mempool.maxmempool || 0); // Calculate usage percentage if (data.mempool.maxmempool && data.mempool.bytes) { const usage = ((data.mempool.bytes / data.mempool.maxmempool) * 100).toFixed(1); document.getElementById('mempoolUsage').textContent = usage + '%'; } else { document.getElementById('mempoolUsage').textContent = '0%'; } } } catch (error) { console.error('Error fetching Palladium info:', error); } } // Update recent blocks async function updateRecentBlocks() { try { const response = await fetch('/api/palladium/blocks/recent'); const data = await response.json(); if (data.error) { console.error('Recent blocks error:', data.error); return; } const tbody = document.getElementById('recentBlocksTable'); tbody.innerHTML = ''; if (data.blocks && data.blocks.length > 0) { data.blocks.forEach(block => { const row = document.createElement('tr'); row.innerHTML = `