mirror of
https://github.com/acedanger/shell.git
synced 2025-12-06 01:10:12 -08:00
feat: Add base HTML template and implement dashboard, logs, and service views
- 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.
This commit is contained in:
159
static/js/app.js
Normal file
159
static/js/app.js
Normal file
@@ -0,0 +1,159 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user