From 7a9054bb3f033c98067b3196378311dae54c5fbf Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 20 Jan 2026 01:31:53 +0000
Subject: [PATCH] =OperationQueue refactor to the JVBase/managers/queue namespace

---
 assets/js/concise/Queue.js |   57 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/assets/js/concise/Queue.js b/assets/js/concise/Queue.js
index db25262..4c9adbc 100644
--- a/assets/js/concise/Queue.js
+++ b/assets/js/concise/Queue.js
@@ -5,6 +5,7 @@
 
 		this.user = window.auth.getUser();
 
+
 		this.canUpdateUI = true;
 		this.isProcessing = false;
 		this.isPolling = false;
@@ -15,6 +16,8 @@
 		this.api = jvbSettings.api;
 		this.endpoint = 'queue';
 
+		this.queueItems = new Map();
+
 		this.init();
 	}
 	init() {
@@ -24,13 +27,14 @@
 		this.initElements();
 		this.initListeners();
 		this.initStore();
-		if (this.canUpdateUI) {
+		if (this.canUpdateUI && this.ui.panel) {
 			this.popup = new window.jvbPopup({
 				popup: this.ui.panel,
 				toggle: this.ui.toggle.button,
 				name: 'Queue Panel',
 			});
 		}
+		this.defineTemplates();
 	}
 
 	initElements() {
@@ -138,6 +142,17 @@
 		if (!this.ui.panel) this.canUpdateUI = false;
 	}
 
+	defineTemplates() {
+		const T = window.jvbTemplates;
+
+		T.define('emptyState');
+		T.define('queueItem', {
+			setup({el, refs, manyRefs, data}) {
+				el.dataset.id = data.id;
+			}
+		});
+	}
+
 
 	initListeners() {
 		this.activityListeners = null;
@@ -161,6 +176,7 @@
 			this.updatePanel('offline');
 		}
 	handleBeforeUnload(e) {
+		if (!this.ui.panel) return;
 		const total = this.getQueueByStatus(this.pendingStatuses).length;
 		if (total > 0) {
 			// Modern browsers ignore custom messages, but this triggers the native dialog
@@ -173,9 +189,12 @@
 			if (!window.targetCheck(e, this.selectors.panel+', '+this.selectors.toggle.button)) return;
 			const refresh = window.targetCheck(e, this.selectors.refresh.button);
 			if (refresh) {
+				this.ui.refresh.button.classList.add('fetching');
 				this.store.clearCache();
 				this.store.clearFilters();
-				this.store.fetch();
+				this.store.fetch().finally(() => {
+					this.ui.refresh.button.classList.remove('fetching');
+				});
 				return;
 			}
 
@@ -266,6 +285,9 @@
 					{name: 'status', keyPath: 'status'},
 					{name: 'type', keyPath: 'type'},
 				],
+				filters: {
+					user: window.auth.getUser()
+				},
 				showLoading: false,
 			}
 		)
@@ -366,9 +388,12 @@
 		}
 		if (statusOrId.length ===0) return;
 		if (!['cancel', 'dismiss', 'retry'].includes(action)) return;
+
 		const shouldRemove = ['cancel', 'dismiss'].includes(action);
 		if (shouldRemove) {
-			statusOrId.forEach(id => this.removeOperationUI(id));
+			statusOrId.forEach(id => {
+				this.removeOperationUI(id)
+			});
 		}
 
 		try {
@@ -396,7 +421,10 @@
 			}
 			statusOrId.forEach(id => {
 				let item = this.getQueue(id);
-				this.notify(`${action}-operation`, item);
+				if (item) {
+					this.notify(`${action}-operation`, item);
+				}
+
 				if (shouldRemove) {
 					this.clearQueue(id);
 				} else {
@@ -463,13 +491,13 @@
 			let requestBody;
 			if (operation.data instanceof FormData) {
 				operation.data.append('id', operation.id);
-				operation.data.append('user', this.user);
+				operation.data.append('user', window.auth.getUser());
 				requestBody = operation.data;
 			} else {
 				requestBody = JSON.stringify({
 					...operation.data,
 					id: operation.id,
-					user: this.user
+					user: window.auth.getUser()
 				});
 				operation.headers['Content-Type'] = 'application/json';
 			}
@@ -633,8 +661,10 @@
 		if (!this.isPolling) return;
 
 		try {
+			this.ui.refresh.button.classList.add('fetching');
 			this.store.clearCache();
 			await this.store.fetch();
+			this.ui.refresh.button.classList.remove('fetching');
 			if (!this.maybeStartPolling()) {
 				this.stopPolling();
 				this.updatePanel('synced');
@@ -649,6 +679,10 @@
 	}
 
 	startCountdown(count, onComplete) {
+		if (!this.ui.refresh.countdown) {
+			console.warn('Countdown element not found');
+			return;
+		}
 		this.ui.refresh.countdown.classList.add('counting');
 		this.ui.refresh.countdown.textContent = count;
 
@@ -727,7 +761,7 @@
 
 		if (sortedOps.length === 0) {
 			window.removeChildren(this.ui.items.container);
-			const empty = window.getTemplate('emptyQueue');
+			const empty = window.jvbTemplates.create('emptyQueue');
 			this.ui.items.container.append(empty);
 			this.a11y.announce('No items in queue');
 			return;
@@ -761,9 +795,7 @@
 	}
 
 	createOperationElement(op) {
-		const el = window.getTemplate('queueItem');
-		el.dataset.id = op.id;
-
+		const el = window.jvbTemplates.create('queueItem', op);
 		const item = {
 			element: el,
 			ui: window.uiFromSelectors(this.selectors.item, el)
@@ -834,7 +866,7 @@
 	}
 
 	updatePanel(status = 'syncing') {
-		if (!this.panelStatuses.includes(status)) return;
+		if (!this.ui.panel || !this.panelStatuses.includes(status)) return;
 		this.ui.panel.classList.remove(...this.panelStatuses);
 		this.ui.panel.classList.add(status);
 	}
@@ -871,7 +903,7 @@
 			case 'completed':
 				return 'Successfully completed';
 			case 'failed':
-				return `Failed: ${item.lastError || 'Unknown error'} (Retry ${item.retries}/${this.config.maxRetries})`;
+				return `Failed: ${item.lastError || 'Unknown error'} (Retry ${item.retries}/${2})`;
 			case 'failed_permanent':
 				return `Failed: ${item.lastError || 'Unknown error'}`;
 			default:
@@ -879,6 +911,7 @@
 		}
 	}
 	toggleQueue(on = true) {
+		if (!this.ui.panel) return;
 		this.ui.panel.hidden = !on;
 		this.ui.toggle.button.hidden = !on;
 	}

--
Gitblit v1.10.0