/** * ComfyUI Queue Manager Frontend JavaScript * Handles the user interface interactions and API communication */ class QueueManager { constructor() { this.apiBase = '/queue'; this.queueItems = []; this.selectedItems = new Set(); this.queueState = 'running'; this.init(); } init() { this.bindEvents(); this.loadQueueItems(); this.updateQueueState(); } bindEvents() { // Control buttons document.getElementById('pause-resume-btn').addEventListener('click', () => { this.toggleQueueState(); }); document.getElementById('refresh-btn').addEventListener('click', () => { this.loadQueueItems(); }); // Bulk actions document.getElementById('archive-selected-btn').addEventListener('click', () => { this.archiveSelected(); }); document.getElementById('delete-selected-btn').addEventListener('click', () => { this.deleteSelected(); }); // Filters document.getElementById('search-input').addEventListener('input', (e) => { this.filterItems(); }); document.getElementById('status-filter').addEventListener('change', (e) => { this.filterItems(); }); } async loadQueueItems() { try { this.showLoading(); // Placeholder for API call - will be implemented in later tasks // const response = await fetch(`${this.apiBase}/items`); // this.queueItems = await response.json(); // Mock data for now this.queueItems = []; this.renderQueueItems(); } catch (error) { console.error('Failed to load queue items:', error); this.showError('Failed to load queue items'); } } async updateQueueState() { try { // Placeholder for API call - will be implemented in later tasks // const response = await fetch(`${this.apiBase}/status`); // const data = await response.json(); // this.queueState = data.state; this.updatePauseResumeButton(); } catch (error) { console.error('Failed to update queue state:', error); } } async toggleQueueState() { try { const newState = this.queueState === 'running' ? 'paused' : 'running'; // Placeholder for API call - will be implemented in later tasks // await fetch(`${this.apiBase}/${newState}`, { method: 'POST' }); this.queueState = newState; this.updatePauseResumeButton(); } catch (error) { console.error('Failed to toggle queue state:', error); } } updatePauseResumeButton() { const btn = document.getElementById('pause-resume-btn'); if (this.queueState === 'running') { btn.textContent = 'Pause'; btn.className = 'btn btn-warning'; } else { btn.textContent = 'Resume'; btn.className = 'btn btn-primary'; } } renderQueueItems() { const container = document.getElementById('queue-items'); if (this.queueItems.length === 0) { container.innerHTML = `

No queue items

Queue items will appear here when workflows are added to the queue.

`; return; } container.innerHTML = this.queueItems.map(item => this.renderQueueItem(item)).join(''); this.bindItemEvents(); } renderQueueItem(item) { const createdAt = new Date(item.created_at).toLocaleString(); const updatedAt = new Date(item.updated_at).toLocaleString(); return `
${item.workflow_name || 'Unnamed Workflow'}
${item.status}
Created: ${createdAt} Updated: ${updatedAt} ID: ${item.id}
${item.error_message ? `
${item.error_message}
` : ''}
${this.getItemActions(item)}
`; } getItemActions(item) { const actions = []; if (item.status === 'archived') { actions.push(''); } else { actions.push(''); } if (item.status === 'pending' || item.status === 'failed') { actions.push(''); } actions.push(''); return actions.join(''); } bindItemEvents() { // Checkbox selection document.querySelectorAll('.item-checkbox').forEach(checkbox => { checkbox.addEventListener('change', (e) => { const itemId = e.target.dataset.id; if (e.target.checked) { this.selectedItems.add(itemId); } else { this.selectedItems.delete(itemId); } }); }); // Individual item actions document.querySelectorAll('.archive-btn').forEach(btn => { btn.addEventListener('click', (e) => { this.archiveItem(e.target.dataset.id); }); }); document.querySelectorAll('.restore-btn').forEach(btn => { btn.addEventListener('click', (e) => { this.restoreItem(e.target.dataset.id); }); }); document.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', (e) => { this.deleteItem(e.target.dataset.id); }); }); document.querySelectorAll('.retry-btn').forEach(btn => { btn.addEventListener('click', (e) => { this.retryItem(e.target.dataset.id); }); }); } filterItems() { const searchTerm = document.getElementById('search-input').value.toLowerCase(); const statusFilter = document.getElementById('status-filter').value; document.querySelectorAll('.queue-item').forEach(item => { const title = item.querySelector('.queue-item-title').textContent.toLowerCase(); const status = item.classList.contains('pending') ? 'pending' : item.classList.contains('running') ? 'running' : item.classList.contains('completed') ? 'completed' : item.classList.contains('failed') ? 'failed' : item.classList.contains('archived') ? 'archived' : ''; const matchesSearch = !searchTerm || title.includes(searchTerm); const matchesStatus = !statusFilter || status === statusFilter; item.style.display = matchesSearch && matchesStatus ? 'block' : 'none'; }); } async archiveSelected() { if (this.selectedItems.size === 0) { alert('Please select items to archive'); return; } try { // Placeholder for API call - will be implemented in later tasks console.log('Archiving items:', Array.from(this.selectedItems)); this.selectedItems.clear(); this.loadQueueItems(); } catch (error) { console.error('Failed to archive items:', error); } } async deleteSelected() { if (this.selectedItems.size === 0) { alert('Please select items to delete'); return; } if (!confirm('Are you sure you want to delete the selected items?')) { return; } try { // Placeholder for API call - will be implemented in later tasks console.log('Deleting items:', Array.from(this.selectedItems)); this.selectedItems.clear(); this.loadQueueItems(); } catch (error) { console.error('Failed to delete items:', error); } } async archiveItem(itemId) { try { // Placeholder for API call - will be implemented in later tasks console.log('Archiving item:', itemId); this.loadQueueItems(); } catch (error) { console.error('Failed to archive item:', error); } } async restoreItem(itemId) { try { // Placeholder for API call - will be implemented in later tasks console.log('Restoring item:', itemId); this.loadQueueItems(); } catch (error) { console.error('Failed to restore item:', error); } } async deleteItem(itemId) { if (!confirm('Are you sure you want to delete this item?')) { return; } try { // Placeholder for API call - will be implemented in later tasks console.log('Deleting item:', itemId); this.loadQueueItems(); } catch (error) { console.error('Failed to delete item:', error); } } async retryItem(itemId) { try { // Placeholder for API call - will be implemented in later tasks console.log('Retrying item:', itemId); this.loadQueueItems(); } catch (error) { console.error('Failed to retry item:', error); } } showLoading() { document.getElementById('queue-items').innerHTML = `

Loading queue items...

`; } showError(message) { document.getElementById('queue-items').innerHTML = `

Error

${message}

`; } } // Initialize the queue manager when the page loads document.addEventListener('DOMContentLoaded', () => { new QueueManager(); });