mirror of
https://github.com/acedanger/shell.git
synced 2025-12-06 06:40:13 -08:00
- Created a base HTML template for consistent layout across pages. - Developed a dashboard page to display backup service metrics and statuses. - Implemented a log viewer for detailed log file inspection. - Added error handling page for better user experience during failures. - Introduced service detail page to show specific service metrics and actions. - Enhanced log filtering and viewing capabilities. - Integrated auto-refresh functionality for real-time updates on metrics. - Created integration and unit test scripts for backup metrics functionality.
160 lines
5.0 KiB
JavaScript
160 lines
5.0 KiB
JavaScript
// JavaScript for Backup Monitor
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
console.log('Backup Monitor loaded');
|
|
|
|
// Update last updated time
|
|
updateLastUpdatedTime();
|
|
|
|
// Set up auto-refresh
|
|
setupAutoRefresh();
|
|
|
|
// Set up service card interactions
|
|
setupServiceCards();
|
|
});
|
|
|
|
function updateLastUpdatedTime() {
|
|
const lastUpdatedElement = document.getElementById('last-updated');
|
|
if (lastUpdatedElement) {
|
|
const now = new Date();
|
|
lastUpdatedElement.textContent = `Last updated: ${now.toLocaleTimeString()}`;
|
|
}
|
|
}
|
|
|
|
function setupAutoRefresh() {
|
|
// Auto-refresh every 30 seconds
|
|
setInterval(function() {
|
|
console.log('Auto-refreshing metrics...');
|
|
refreshMetrics();
|
|
}, 30000);
|
|
}
|
|
|
|
function setupServiceCards() {
|
|
// Add click handlers for service cards
|
|
const serviceCards = document.querySelectorAll('.service-card');
|
|
serviceCards.forEach(card => {
|
|
card.addEventListener('click', function(e) {
|
|
// Don't trigger if clicking on buttons
|
|
if (e.target.tagName === 'A' || e.target.tagName === 'BUTTON') {
|
|
return;
|
|
}
|
|
|
|
const serviceName = this.dataset.service;
|
|
if (serviceName) {
|
|
window.location.href = `/service/${serviceName}`;
|
|
}
|
|
});
|
|
|
|
// Add hover effects
|
|
card.style.cursor = 'pointer';
|
|
});
|
|
}
|
|
|
|
function refreshMetrics() {
|
|
// Show loading indicator
|
|
const refreshButton = document.querySelector('[onclick="refreshMetrics()"]');
|
|
if (refreshButton) {
|
|
const icon = refreshButton.querySelector('i');
|
|
if (icon) {
|
|
icon.classList.add('fa-spin');
|
|
}
|
|
refreshButton.disabled = true;
|
|
}
|
|
|
|
// Reload the page to get fresh data
|
|
setTimeout(() => {
|
|
location.reload();
|
|
}, 500);
|
|
}
|
|
|
|
function downloadBackup(serviceName) {
|
|
console.log(`Downloading backup for service: ${serviceName}`);
|
|
|
|
// Create a temporary link to trigger download
|
|
const link = document.createElement('a');
|
|
link.href = `/api/backup/download/${serviceName}`;
|
|
link.download = `${serviceName}-backup.tar.gz`;
|
|
link.target = '_blank';
|
|
|
|
// Append to body, click, and remove
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
}
|
|
|
|
// Utility functions
|
|
function formatFileSize(bytes) {
|
|
if (bytes === 0) return '0 Bytes';
|
|
|
|
const k = 1024;
|
|
const sizes = ['Bytes', '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];
|
|
}
|
|
|
|
function formatDuration(seconds) {
|
|
if (seconds < 60) {
|
|
return `${seconds}s`;
|
|
} else if (seconds < 3600) {
|
|
const minutes = Math.floor(seconds / 60);
|
|
const remainingSeconds = seconds % 60;
|
|
return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
|
|
} else {
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
|
|
}
|
|
}
|
|
|
|
function showNotification(message, type = 'info') {
|
|
// Create notification element
|
|
const notification = document.createElement('div');
|
|
notification.className = `alert alert-${type} alert-dismissible fade show position-fixed`;
|
|
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; max-width: 300px;';
|
|
notification.innerHTML = `
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
`;
|
|
|
|
// Add to page
|
|
document.body.appendChild(notification);
|
|
|
|
// Auto-remove after 5 seconds
|
|
setTimeout(() => {
|
|
if (notification.parentNode) {
|
|
notification.parentNode.removeChild(notification);
|
|
}
|
|
}, 5000);
|
|
}
|
|
|
|
// Health check functionality
|
|
function checkSystemHealth() {
|
|
fetch('/health')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const statusIndicator = document.getElementById('status-indicator');
|
|
if (statusIndicator) {
|
|
if (data.status === 'healthy') {
|
|
statusIndicator.className = 'text-success';
|
|
statusIndicator.innerHTML = '<i class="fas fa-circle me-1"></i>Online';
|
|
} else {
|
|
statusIndicator.className = 'text-warning';
|
|
statusIndicator.innerHTML = '<i class="fas fa-exclamation-circle me-1"></i>Issues';
|
|
}
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Health check failed:', error);
|
|
const statusIndicator = document.getElementById('status-indicator');
|
|
if (statusIndicator) {
|
|
statusIndicator.className = 'text-danger';
|
|
statusIndicator.innerHTML = '<i class="fas fa-times-circle me-1"></i>Offline';
|
|
}
|
|
});
|
|
}
|
|
|
|
// Run health check every minute
|
|
setInterval(checkSystemHealth, 60000);
|
|
checkSystemHealth(); // Run immediately
|