(function() { "use strict"; const API_BASE = "http://localhost:8080/api/v1"; let currentTab = "dashboard"; // Initialize $(document).ready(function() { setupTabs(); loadDashboard(); setupEventHandlers(); }); function setupTabs() { $("a[data-tab]").on("click", function(e) { e.preventDefault(); const tab = $(this).data("tab"); switchTab(tab); }); } function switchTab(tab) { $(".tab-content").hide(); $(".nav li").removeClass("active"); $(`#${tab}`).show(); $(`a[data-tab="${tab}"]`).parent().addClass("active"); currentTab = tab; // Load tab-specific data switch(tab) { case "dashboard": loadDashboard(); break; case "storage": loadRepositories(); break; case "tape": loadTapeLibrary(); break; case "iscsi": loadiSCSITargets(); break; case "bacula": loadBaculaStatus(); break; case "logs": loadLogs(); break; } } function apiCall(endpoint, method, data) { return new Promise((resolve, reject) => { const options = { url: `${API_BASE}${endpoint}`, method: method || "GET", contentType: "application/json", success: resolve, error: function(xhr, status, error) { reject(new Error(error || xhr.responseText)); } }; if (data) { options.data = JSON.stringify(data); } $.ajax(options); }); } function loadDashboard() { apiCall("/dashboard") .then(data => { // Update disk stats const disk = data.disk || {}; $("#disk-stats").html(`
Repositories: ${disk.repositories || 0}
Total: ${formatBytes(disk.total_capacity || 0)}
Used: ${formatBytes(disk.used_capacity || 0)}
`); // Update tape stats const tape = data.tape || {}; $("#tape-stats").html(`Status: ${tape.library_status || "unknown"}
Active Drives: ${tape.drives_active || 0}
Total Slots: ${tape.total_slots || 0}
`); // Update iSCSI stats const iscsi = data.iscsi || {}; $("#iscsi-stats").html(`Targets: ${iscsi.targets || 0}
Sessions: ${iscsi.sessions || 0}
`); // Update Bacula stats const bacula = data.bacula || {}; $("#bacula-stats").html(`Status: ${bacula.status || "unknown"}
`); // Update alerts const alerts = data.alerts || []; if (alerts.length > 0) { let alertsHtml = "No alerts
"); } }) .catch(err => { console.error("Failed to load dashboard:", err); $("#disk-stats, #tape-stats, #iscsi-stats, #bacula-stats").html("Error loading data
"); }); } function loadRepositories() { apiCall("/disk/repositories") .then(repos => { let html = ""; if (repos.length === 0) { html = "Status: ${library.status}
Model: ${library.model || "N/A"}
Total Slots: ${library.total_slots}
Active Drives: ${library.active_drives}
`); // Drives let drivesHtml = ""; if (drives.length === 0) { drivesHtml = "No drives detected
"; } else { drives.forEach(drive => { drivesHtml += `| Slot | Barcode | Status |
|---|---|---|
| No slots | ||
| ${slot.number} | ${slot.barcode || "N/A"} | ${slot.status} |
Status: ${status.status}
${status.version ? `Version: ${status.version}
` : ""} ${status.pid ? `PID: ${status.pid}
` : ""} `); }) .catch(err => { console.error("Failed to load Bacula status:", err); }); } function loadLogs() { const service = $("#log-service").val(); apiCall(`/logs/${service}?lines=100`) .then(logs => { let logsHtml = ""; logs.forEach(entry => { logsHtml += `[${entry.timestamp}] ${entry.level}: ${entry.message}\n`; }); $("#logs-content").text(logsHtml); }) .catch(err => { console.error("Failed to load logs:", err); $("#logs-content").text("Error loading logs: " + err.message); }); } function setupEventHandlers() { $("#inventory-btn").on("click", function() { apiCall("/tape/inventory", "POST") .then(() => { alert("Inventory started"); loadTapeLibrary(); }) .catch(err => alert("Failed to start inventory: " + err.message)); }); $("#bacula-inventory-btn").on("click", function() { apiCall("/bacula/inventory", "POST") .then(() => alert("Inventory started")) .catch(err => alert("Failed to start inventory: " + err.message)); }); $("#bacula-restart-btn").on("click", function() { if (confirm("Restart Bacula Storage Daemon?")) { apiCall("/bacula/restart", "POST") .then(() => { alert("Restart initiated"); setTimeout(loadBaculaStatus, 2000); }) .catch(err => alert("Failed to restart: " + err.message)); } }); $("#refresh-logs-btn").on("click", loadLogs); $("#log-service").on("change", loadLogs); $("#download-bundle-btn").on("click", function() { window.location.href = `${API_BASE}/diagnostics/bundle`; }); } function formatBytes(bytes) { if (bytes === 0) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB", "TB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i]; } // Global functions for inline handlers window.deleteRepository = function(id) { if (confirm("Delete this repository?")) { apiCall(`/disk/repositories/${id}`, "DELETE") .then(() => { alert("Repository deleted"); loadRepositories(); }) .catch(err => alert("Failed to delete: " + err.message)); } }; window.applyTarget = function(id) { apiCall(`/iscsi/targets/${id}/apply`, "POST") .then(() => alert("Target configuration applied")) .catch(err => alert("Failed to apply: " + err.message)); }; window.deleteTarget = function(id) { if (confirm("Delete this iSCSI target?")) { apiCall(`/iscsi/targets/${id}`, "DELETE") .then(() => { alert("Target deleted"); loadiSCSITargets(); }) .catch(err => alert("Failed to delete: " + err.message)); } }; })();