diff --git a/db-status.js b/db-status.js index 6cfd89b..d072f01 100644 --- a/db-status.js +++ b/db-status.js @@ -7,24 +7,192 @@ class DatabaseStatusMonitor { connection: document.getElementById('dbConnection'), latency: document.getElementById('dbLatency'), write: document.getElementById('dbWrite'), - timestamp: document.getElementById('dbTimestamp') + timestamp: document.getElementById('dbTimestamp'), + retryBtn: document.getElementById('dbRetryBtn'), + statusBar: document.getElementById('dbStatusBar'), + detailsPanel: document.getElementById('dbStatusDetails'), + errorBanner: document.getElementById('sqlErrorBanner'), + errorMessage: document.getElementById('sqlErrorMessage'), + errorDetails: document.getElementById('sqlErrorDetails') }; + this.logs = []; + this.maxLogs = 50; + + // Make status bar clickable to show details + if (this.elements.statusBar) { + this.elements.statusBar.style.cursor = 'pointer'; + this.elements.statusBar.addEventListener('click', (e) => { + // Don't toggle if clicking the retry button + if (!e.target.closest('.db-retry-btn')) { + this.toggleDetails(); + } + }); + } + } + + addLog(message, type = 'info') { + const timestamp = new Date().toLocaleTimeString('en-US', { + hour12: false, + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }); + + const logEntry = { + timestamp, + message, + type // 'info', 'success', 'error', 'warning' + }; + + this.logs.unshift(logEntry); + if (this.logs.length > this.maxLogs) { + this.logs.pop(); + } + + // Console logging with emoji + const emoji = { + 'info': 'ℹ️', + 'success': '✅', + 'error': '❌', + 'warning': '⚠️' + }; + + console.log(`${emoji[type]} [DB-STATUS ${timestamp}] ${message}`); + + // Update logs display + this.updateLogsDisplay(); + } + + updateLogsDisplay() { + const logsContainer = document.getElementById('detailLogs'); + if (!logsContainer) return; + + logsContainer.innerHTML = '
Recent Logs:
'; + this.logs.slice(0, 20).forEach(log => { + const logDiv = document.createElement('div'); + logDiv.className = `db-log-entry db-log-${log.type}`; + logDiv.textContent = `[${log.timestamp}] ${log.message}`; + logsContainer.appendChild(logDiv); + }); + } + + toggleDetails() { + if (this.elements.detailsPanel) { + const isHidden = this.elements.detailsPanel.style.display === 'none'; + this.elements.detailsPanel.style.display = isHidden ? 'block' : 'none'; + if (isHidden) { + this.addLog('Details panel opened', 'info'); + } + } } async checkStatus() { + this.addLog('Checking database status...', 'info'); + try { const response = await fetch('/api/db-status'); const data = await response.json(); + this.addLog(`Response received: ${data.connected ? 'Connected' : 'Disconnected'}`, + data.connected ? 'success' : 'error'); + + if (data.error) { + this.addLog(`Error: ${data.error}`, 'error'); + } + + if (data.poolStats) { + this.addLog(`Pool: ${data.poolStats.freeConnections}/${data.poolStats.totalConnections} free, ${data.poolStats.queuedRequests} queued`, 'info'); + } + this.updateUI(data); + this.updateDetails(data); + this.updateErrorBanner(data); } catch (error) { + this.addLog(`Failed to fetch status: ${error.message}`, 'error'); console.error('Failed to fetch database status:', error); - this.updateUI({ + const errorData = { connected: false, latency: 0, writeCapable: false, error: 'Failed to connect to server' - }); + }; + this.updateUI(errorData); + this.updateErrorBanner(errorData); + } + } + + updateErrorBanner(status) { + if (!this.elements.errorBanner) return; + + if (!status.connected || status.error) { + // Show error banner + this.elements.errorBanner.style.display = 'block'; + + // Update error message + if (this.elements.errorMessage) { + this.elements.errorMessage.textContent = status.error || 'Connection failed'; + } + + // Update error details + if (this.elements.errorDetails) { + const details = []; + + if (status.host) { + details.push(`🖥️ Host: ${status.host}`); + } + if (status.database) { + details.push(`🗄️ Database: ${status.database}`); + } + if (status.user) { + details.push(`👤 User: ${status.user}`); + } + if (status.latency !== undefined) { + details.push(`⏱️ Latency: ${status.latency}ms`); + } + if (status.poolStats) { + details.push(`🔗 Pool: ${status.poolStats.freeConnections}/${status.poolStats.totalConnections} free`); + } + + details.push(`🕐 Last Check: ${new Date().toLocaleTimeString()}`); + + this.elements.errorDetails.innerHTML = details.map(d => + `
${d}
` + ).join(''); + } + } else { + // Hide error banner when connected + this.elements.errorBanner.style.display = 'none'; + } + } + + updateDetails(status) { + // Update detail panel + const detailStatus = document.getElementById('detailStatus'); + const detailHost = document.getElementById('detailHost'); + const detailDatabase = document.getElementById('detailDatabase'); + const detailError = document.getElementById('detailError'); + + if (detailStatus) { + detailStatus.textContent = status.connected ? '✅ Connected' : '❌ Disconnected'; + detailStatus.style.color = status.connected ? '#10b981' : '#ef4444'; + } + + if (detailHost) { + detailHost.textContent = status.host || 'unknown'; + } + + if (detailDatabase) { + detailDatabase.textContent = status.database || 'unknown'; + } + + if (detailError) { + if (status.error) { + detailError.textContent = status.error; + detailError.style.color = '#ef4444'; + } else { + detailError.textContent = 'None'; + detailError.style.color = '#10b981'; + } } } @@ -94,8 +262,36 @@ class DatabaseStatusMonitor { this.elements.timestamp.textContent = timeString; } + async retryConnection() { + this.addLog('🔄 Manual retry triggered', 'info'); + + // Visual feedback on button + if (this.elements.retryBtn) { + this.elements.retryBtn.disabled = true; + this.elements.retryBtn.classList.add('retrying'); + const originalText = this.elements.retryBtn.innerHTML; + this.elements.retryBtn.innerHTML = ` + + + + Retrying... + `; + + await this.checkStatus(); + + setTimeout(() => { + this.elements.retryBtn.disabled = false; + this.elements.retryBtn.classList.remove('retrying'); + this.elements.retryBtn.innerHTML = originalText; + }, 1000); + } else { + await this.checkStatus(); + } + } + start() { // Initial check + this.addLog('Database status monitor started', 'success'); this.checkStatus(); // Set up periodic checks @@ -110,6 +306,7 @@ class DatabaseStatusMonitor { if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; + this.addLog('Database status monitor stopped', 'warning'); console.log('⏹️ Database status monitor stopped'); } } diff --git a/index.html b/index.html index d367eb8..93f8aea 100644 --- a/index.html +++ b/index.html @@ -180,6 +180,53 @@ Last Check: -- +
+ +
+ + + + + + +