300 lines
9.6 KiB
JavaScript
300 lines
9.6 KiB
JavaScript
// AutoBackups JavaScript Application
|
|
|
|
class AutoBackupsApp {
|
|
constructor() {
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.initializeTheme();
|
|
this.updateCurrentTime();
|
|
this.setupEventListeners();
|
|
|
|
// Update time every minute
|
|
setInterval(() => this.updateCurrentTime(), 60000);
|
|
}
|
|
|
|
updateCurrentTime() {
|
|
const now = new Date();
|
|
const timeString = now.toLocaleString('es-ES', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
|
|
const timeElement = document.getElementById('current-time');
|
|
if (timeElement) {
|
|
timeElement.textContent = timeString;
|
|
}
|
|
}
|
|
|
|
// Theme Management
|
|
initializeTheme() {
|
|
// Load saved theme from localStorage or default to light
|
|
const savedTheme = localStorage.getItem('theme') || 'light';
|
|
this.setTheme(savedTheme);
|
|
}
|
|
|
|
setTheme(theme) {
|
|
const htmlElement = document.documentElement;
|
|
const themeIcon = document.getElementById('theme-icon');
|
|
|
|
if (theme === 'dark') {
|
|
htmlElement.setAttribute('data-theme', 'dark');
|
|
if (themeIcon) {
|
|
themeIcon.className = 'bi bi-moon-fill';
|
|
}
|
|
} else {
|
|
htmlElement.removeAttribute('data-theme');
|
|
if (themeIcon) {
|
|
themeIcon.className = 'bi bi-sun-fill';
|
|
}
|
|
}
|
|
|
|
localStorage.setItem('theme', theme);
|
|
}
|
|
|
|
toggleTheme() {
|
|
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
|
this.setTheme(newTheme);
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// Theme toggle button
|
|
const themeToggleBtn = document.getElementById('theme-toggle');
|
|
if (themeToggleBtn) {
|
|
themeToggleBtn.addEventListener('click', () => this.toggleTheme());
|
|
}
|
|
|
|
// Global backup all button
|
|
const backupAllBtn = document.getElementById('backup-all-btn');
|
|
if (backupAllBtn) {
|
|
backupAllBtn.addEventListener('click', () => this.backupAllProjects());
|
|
}
|
|
|
|
// Save project configuration
|
|
const saveConfigBtn = document.getElementById('save-project-config-btn');
|
|
if (saveConfigBtn) {
|
|
saveConfigBtn.addEventListener('click', () => this.saveProjectConfig());
|
|
}
|
|
}
|
|
|
|
backupAllProjects() {
|
|
this.showAlert('info', 'Iniciando backup de todos los proyectos habilitados...');
|
|
|
|
// Get all enabled projects and trigger backup
|
|
fetch('/api/projects')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.error) {
|
|
this.showAlert('danger', `Error: ${data.error}`);
|
|
return;
|
|
}
|
|
|
|
const enabledProjects = data.projects.filter(project =>
|
|
project.schedule_config && project.schedule_config.enabled
|
|
);
|
|
|
|
if (enabledProjects.length === 0) {
|
|
this.showAlert('warning', 'No hay proyectos habilitados para backup.');
|
|
return;
|
|
}
|
|
|
|
// Backup each enabled project
|
|
let completed = 0;
|
|
enabledProjects.forEach(project => {
|
|
fetch(`/api/projects/${project.id}/backup`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' }
|
|
})
|
|
.then(response => response.json())
|
|
.then(backupData => {
|
|
completed++;
|
|
if (completed === enabledProjects.length) {
|
|
this.showAlert('success',
|
|
`Backup completado para ${enabledProjects.length} proyectos.`);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error(`Error backing up project ${project.id}:`, error);
|
|
});
|
|
});
|
|
})
|
|
.catch(error => {
|
|
this.showAlert('danger', `Error de conexión: ${error.message}`);
|
|
});
|
|
}
|
|
|
|
saveProjectConfig() {
|
|
const projectId = document.getElementById('modal-project-id').value;
|
|
const schedule = document.getElementById('modal-project-schedule').value;
|
|
const time = document.getElementById('modal-project-time').value;
|
|
const enabled = document.getElementById('modal-project-enabled').checked;
|
|
|
|
const config = {
|
|
schedule_config: {
|
|
schedule: schedule,
|
|
schedule_time: time,
|
|
enabled: enabled
|
|
}
|
|
};
|
|
|
|
fetch(`/api/projects/${projectId}/config`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(config)
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.error) {
|
|
this.showAlert('danger', `Error: ${data.error}`);
|
|
} else {
|
|
this.showAlert('success', 'Configuración guardada correctamente.');
|
|
|
|
// Close modal
|
|
const modal = bootstrap.Modal.getInstance(
|
|
document.getElementById('projectConfigModal')
|
|
);
|
|
if (modal) {
|
|
modal.hide();
|
|
}
|
|
|
|
// Refresh page after a short delay
|
|
setTimeout(() => location.reload(), 1500);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
this.showAlert('danger', `Error de conexión: ${error.message}`);
|
|
});
|
|
}
|
|
|
|
showAlert(type, message, duration = 5000) {
|
|
const alertsContainer = document.getElementById('alerts-container');
|
|
if (!alertsContainer) return;
|
|
|
|
const alertId = 'alert-' + Date.now();
|
|
const alertHtml = `
|
|
<div class="alert alert-${type} alert-dismissible fade show fade-in" role="alert" id="${alertId}">
|
|
<i class="bi bi-${this.getAlertIcon(type)}"></i>
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
`;
|
|
|
|
alertsContainer.insertAdjacentHTML('beforeend', alertHtml);
|
|
|
|
// Auto-dismiss after duration
|
|
if (duration > 0) {
|
|
setTimeout(() => {
|
|
const alertElement = document.getElementById(alertId);
|
|
if (alertElement) {
|
|
const alert = new bootstrap.Alert(alertElement);
|
|
alert.close();
|
|
}
|
|
}, duration);
|
|
}
|
|
}
|
|
|
|
getAlertIcon(type) {
|
|
const icons = {
|
|
'success': 'check-circle',
|
|
'danger': 'exclamation-triangle',
|
|
'warning': 'exclamation-triangle',
|
|
'info': 'info-circle',
|
|
'primary': 'info-circle',
|
|
'secondary': 'info-circle'
|
|
};
|
|
return icons[type] || 'info-circle';
|
|
}
|
|
|
|
// Utility method to format file sizes
|
|
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];
|
|
}
|
|
|
|
// Utility method to format dates
|
|
formatDate(dateString) {
|
|
if (!dateString) return 'N/A';
|
|
|
|
const date = new Date(dateString);
|
|
return date.toLocaleString('es-ES', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
}
|
|
|
|
// Method to show loading state
|
|
showLoading(element) {
|
|
if (element) {
|
|
element.classList.add('loading');
|
|
const originalContent = element.innerHTML;
|
|
element.innerHTML = '<span class="spinner-border spinner-border-sm" role="status"></span> Cargando...';
|
|
return originalContent;
|
|
}
|
|
}
|
|
|
|
// Method to hide loading state
|
|
hideLoading(element, originalContent) {
|
|
if (element && originalContent) {
|
|
element.classList.remove('loading');
|
|
element.innerHTML = originalContent;
|
|
}
|
|
}
|
|
|
|
// Method to make API calls with error handling
|
|
async apiCall(url, options = {}) {
|
|
try {
|
|
const response = await fetch(url, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...options.headers
|
|
},
|
|
...options
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.error || `HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
return data;
|
|
} catch (error) {
|
|
console.error('API call failed:', error);
|
|
this.showAlert('danger', `Error de API: ${error.message}`);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Global functions for backward compatibility
|
|
function showAlert(type, message, duration = 5000) {
|
|
if (window.autobackupsApp) {
|
|
window.autobackupsApp.showAlert(type, message, duration);
|
|
}
|
|
}
|
|
|
|
// Initialize app when DOM is loaded
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
window.autobackupsApp = new AutoBackupsApp();
|
|
});
|
|
|
|
// Export for modules if needed
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = AutoBackupsApp;
|
|
}
|