/** * Live Status Monitor for Container Creation * Provides real-time updates similar to Proxmox task viewer */ class LiveStatusMonitor { constructor(taskId, logContainer) { this.taskId = taskId; this.logContainer = logContainer; this.pollInterval = 1000; // Poll every second this.init(); } init() { console.log(`Initializing live status for task: ${this.taskId}`); // Initial request with error handling $.get(`/manager/task/${this.taskId}/status/`) .done((data) => { console.log('Initial status data received:', data); this.updateDisplay(data); // Start polling only after successful initial request this.startPolling(); }) .fail((xhr, status, error) => { console.error('Failed to get initial status:', error, xhr.responseText); this.showError(`Failed to connect to live status: ${error}`); // Still try to start polling in case it's a temporary issue setTimeout(() => { this.startPolling(); }, 2000); }); } startPolling() { setInterval(() => { $.get(`/manager/task/${this.taskId}/status/`) .done((data) => { this.updateDisplay(data); }) .fail((xhr, status, error) => { console.error('Polling error:', error); // Don't show error for every polling failure }); }, this.pollInterval); } showError(message) { const logContent = this.logContainer.querySelector('.live-log-content'); if (logContent) { logContent.innerHTML = `
${message}
`; } } updateDisplay(data) { const logContent = this.logContainer.querySelector('.live-log-content'); if (!logContent) return; const logs = data.logs || {}; const steps = logs.steps || []; if (steps.length === 0) { logContent.innerHTML = '
Waiting for status updates...
'; return; } // Track existing entries to highlight new ones const existingCount = logContent.querySelectorAll('.log-entry').length; logContent.innerHTML = ''; steps.forEach((step, index) => { const entry = this.createLogEntry(step); if (index >= existingCount) { entry.classList.add('new'); } logContent.appendChild(entry); }); // Auto-scroll to bottom logContent.scrollTop = logContent.scrollHeight; } createLogEntry(step) { const entry = document.createElement('div'); entry.className = 'log-entry'; const timestamp = new Date(step.timestamp).toLocaleTimeString(); const message = step.message || ''; entry.innerHTML = `
${timestamp}
${this.escapeHtml(message)}
`; return entry; } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } } let liveStatus = null; function initLiveStatus(taskId, containerId) { const container = document.getElementById(containerId); if (container && taskId) { liveStatus = new LiveStatusMonitor(taskId, container); } }