globalquota/js/admin-settings.js

359 lines
13 KiB
JavaScript

/**
* GlobalQuota Admin Settings JavaScript
* Maneja el gráfico donut y las acciones de administración
*/
(function() {
'use strict';
// Validate Nextcloud environment
if (typeof OC === 'undefined' || typeof t === 'undefined') {
console.error('GlobalQuota: Nextcloud environment not available');
return;
}
console.log('GlobalQuota admin JS loaded ✅');
let quotaChart = null;
let chartInitialized = false;
let dataLoaded = false;
function initChart() {
const canvas = document.getElementById('globalquota-chart');
if (!canvas) {
console.warn('GlobalQuota: canvas #globalquota-chart no encontrado');
return;
}
if (typeof Chart === 'undefined') {
console.warn('GlobalQuota: Chart.js no está disponible');
return;
}
try {
const ctx = canvas.getContext('2d');
quotaChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [t('globalquota', 'Used'), t('globalquota', 'Free')],
datasets: [{
data: [0, 100],
backgroundColor: ['#e74c3c', '#ecf0f1'],
borderWidth: 0,
cutout: '70%'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
padding: 20,
usePointStyle: true,
font: {
size: 12
}
}
},
tooltip: {
callbacks: {
label: function(context) {
const label = context.label || '';
const value = formatBytes(context.raw);
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = total > 0 ? ((context.raw / total) * 100).toFixed(1) : '0.0';
return `${label}: ${value} (${percentage}%)`;
}
}
}
}
}
});
chartInitialized = true;
console.log('GlobalQuota: Gráfico inicializado correctamente');
} catch (error) {
console.error('GlobalQuota: Error al inicializar el gráfico:', error);
quotaChart = null;
chartInitialized = false;
}
}
function loadQuotaData() {
// Prevent multiple simultaneous requests
if (dataLoaded) {
console.log('GlobalQuota: Data already loading, skipping...');
return;
}
dataLoaded = true;
console.log('GlobalQuota: Cargando datos...');
// Clear any previous errors
const errorEl = document.getElementById('quota-error');
if (errorEl) {
errorEl.style.display = 'none';
errorEl.textContent = '';
}
// Try the new /status endpoint first
fetch(OC.generateUrl('/apps/globalquota/status'))
.then(async response => {
console.log('GlobalQuota: Respuesta del endpoint /status:', response.status);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const text = await response.text();
if (!text) {
throw new Error('Empty response');
}
try {
const data = JSON.parse(text);
console.log('GlobalQuota: Datos recibidos de /status:', data);
return data;
} catch (parseError) {
console.warn('GlobalQuota: respuesta no-JSON', text);
throw new Error('Invalid JSON response');
}
})
.then(data => {
if (data && typeof data.used !== 'undefined' && typeof data.total !== 'undefined') {
processQuotaData(data);
} else {
throw new Error('Invalid data structure');
}
})
.catch(error => {
console.log('GlobalQuota: /status failed, trying /quota endpoint...', error.message);
// Fallback to legacy /quota endpoint
return fetch(OC.generateUrl('/apps/globalquota/quota'))
.then(response => {
console.log('GlobalQuota: Respuesta del endpoint /quota:', response.status);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('GlobalQuota: Datos recibidos de /quota:', data);
if (data && typeof data.used !== 'undefined' && typeof data.total !== 'undefined') {
processQuotaData(data);
} else {
throw new Error('Invalid quota data structure');
}
})
.catch(fallbackError => {
console.error('GlobalQuota: Both endpoints failed:', fallbackError);
showError('Failed to load quota data from both endpoints');
});
})
.finally(() => {
dataLoaded = false;
});
}
function processQuotaData(data) {
// Unified calculation logic for both chart and stats
const used = Number(data.used) || 0;
const total = Number(data.total) || 0;
const available = Number(data.available || data.free || 0);
// Calculate free space with unified logic
let free;
if (total > 0) {
// If we have total, calculate free as total - used
free = Math.max(0, total - used);
} else if (available > 0) {
// If no total but we have available, use that
free = available;
} else {
// Fallback: assume no free space if we can't calculate
free = 0;
}
// Calculate percentage
const percentage = total > 0 ? ((used / total) * 100) : 0;
// Create normalized data object
const normalizedData = {
used: used,
free: free,
total: total > 0 ? total : (used + free),
percentage: percentage,
formatted: data.formatted || {}
};
console.log('GlobalQuota: Normalized data:', normalizedData);
// Update both chart and stats with the same data
updateChart(normalizedData);
updateStats(normalizedData);
}
function updateChart(data) {
if (!quotaChart || !chartInitialized) {
console.warn('GlobalQuota: Chart not initialized, skipping update');
return;
}
console.log('GlobalQuota: Updating chart with:', {
used: data.used,
free: data.free,
total: data.total
});
quotaChart.data.datasets[0].data = [data.used, data.free];
// Update colors based on usage percentage
let usedColor = '#2ecc71'; // Green
if (data.percentage > 90) {
usedColor = '#e74c3c'; // Red
} else if (data.percentage > 75) {
usedColor = '#f39c12'; // Orange
} else if (data.percentage > 50) {
usedColor = '#f1c40f'; // Yellow
}
quotaChart.data.datasets[0].backgroundColor = [usedColor, '#ecf0f1'];
quotaChart.update('active');
}
function updateStats(data) {
// Use the same normalized data for stats
const elems = {
'quota-used': data.formatted?.used || formatBytes(data.used),
'quota-free': data.formatted?.free || data.formatted?.available || formatBytes(data.free),
'quota-total': data.formatted?.total || formatBytes(data.total),
'quota-percentage': data.percentage.toFixed(1) + '%'
};
console.log('GlobalQuota: Updating stats with:', elems);
Object.entries(elems).forEach(([id, val]) => {
const el = document.getElementById(id);
if (el) {
el.textContent = val;
} else {
console.warn(`GlobalQuota: Element #${id} not found`);
}
});
}
function formatBytes(bytes) {
if (!bytes || isNaN(bytes) || bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
const idx = Math.max(0, Math.min(i, sizes.length - 1));
const num = bytes / Math.pow(k, idx);
return num.toFixed(2) + ' ' + sizes[idx];
}
function showError(msg) {
console.error('GlobalQuota:', msg);
// Try to show error in dedicated error element
const errorEl = document.getElementById('quota-error');
if (errorEl) {
errorEl.style.display = 'block';
errorEl.textContent = msg;
}
// Also try Nextcloud notification system
try {
if (OC && OC.Notification) {
OC.Notification.showTemporary(msg, { type: 'error' });
}
} catch (e) {
console.warn('GlobalQuota: Could not show notification:', e);
}
}
function loadChartJS() {
return new Promise((resolve, reject) => {
if (typeof Chart !== 'undefined') {
console.log('GlobalQuota: Chart.js already available');
resolve();
return;
}
console.log('GlobalQuota: Loading Chart.js...');
// Try to load from CDN first
const cdnScript = document.createElement('script');
cdnScript.src = 'https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js';
cdnScript.onload = function() {
console.log('GlobalQuota: Chart.js loaded from CDN');
resolve();
};
cdnScript.onerror = function() {
console.warn('GlobalQuota: CDN failed, trying local Chart.js...');
// Fallback to local file
const localScript = document.createElement('script');
localScript.src = OC.filePath('globalquota', 'js', 'chart.min.js');
localScript.onload = function() {
console.log('GlobalQuota: Chart.js loaded locally');
resolve();
};
localScript.onerror = function() {
console.error('GlobalQuota: Failed to load Chart.js from both CDN and local');
reject(new Error('Chart.js not available'));
};
document.head.appendChild(localScript);
};
document.head.appendChild(cdnScript);
});
}
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
console.log('GlobalQuota: DOM loaded, iniciando...');
// Initialize chart if canvas exists
const canvas = document.getElementById('globalquota-chart');
if (canvas) {
console.log('GlobalQuota: Canvas found, loading Chart.js...');
loadChartJS()
.then(() => {
initChart();
// Load data only after chart is ready
loadQuotaData();
})
.catch(error => {
console.error('GlobalQuota: Failed to initialize chart:', error);
showError('Chart visualization not available');
// Still load data for stats even if chart fails
loadQuotaData();
});
} else {
console.warn('GlobalQuota: Canvas #globalquota-chart not found');
// Load data for stats only
loadQuotaData();
}
// Set up refresh button
const refreshBtn = document.getElementById('refresh-quota');
if (refreshBtn) {
refreshBtn.addEventListener('click', function() {
console.log('GlobalQuota: Refresh button clicked');
loadQuotaData();
});
}
});
})();