Skip to main content

max / makenotwork

Add upload queue display, allow multiple current versions Show a list of all queued files above the progress bar during upload. Each entry shows filename, label, and size. Status updates as each file progresses: - (pending), ... (uploading), OK (done), ! (error). Multiple versions with the same version number are all marked current (e.g. macOS + Linux + Windows builds at v0.3.1). Only older version numbers get unset. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-10 21:55 UTC
Commit: 6ef52894394b43475a44955021484d95e781c2e0
Parent: 5e8da77
4 files changed, +43 insertions, -7 deletions
@@ -24,9 +24,10 @@ pub async fn create_version(
24 24 ) -> Result<DbVersion> {
25 25 let mut tx = pool.begin().await?;
26 26
27 - // Unset any existing current version for this item
28 - sqlx::query("UPDATE versions SET is_current = false WHERE item_id = $1")
27 + // Unset current on older version numbers (versions with the same number stay current)
28 + sqlx::query("UPDATE versions SET is_current = false WHERE item_id = $1 AND version_number != $2")
29 29 .bind(item_id)
30 + .bind(version_number)
30 31 .execute(&mut *tx)
31 32 .await?;
32 33
@@ -206,9 +206,38 @@
206 206 document.getElementById('new-version-form').classList.add('hidden');
207 207 document.getElementById('version-upload-progress').classList.remove('hidden');
208 208
209 + // Build queue display
210 + var queueEl = document.getElementById('version-upload-queue');
211 + queueEl.innerHTML = '';
212 + for (var q = 0; q < entries.length; q++) {
213 + var li = document.createElement('div');
214 + li.id = 'queue-item-' + entries[q].idx;
215 + li.style.cssText = 'display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0; font-size: 0.85rem;';
216 + var labelInput = document.querySelector('.version-label-input[data-idx="' + entries[q].idx + '"]');
217 + var labelText = labelInput ? labelInput.value.trim() : '';
218 + var displayName = entries[q].file.name + (labelText ? ' (' + escapeHtml(labelText) + ')' : '');
219 + li.innerHTML = '<span class="queue-status" style="width: 1.5em; text-align: center; opacity: 0.5;">-</span><span style="flex: 1;">' + displayName + '</span><span class="queue-size" style="opacity: 0.5;">' + formatSize(entries[q].file.size) + '</span>';
220 + queueEl.appendChild(li);
221 + }
222 +
209 223 uploadSequentially(entries, 0, versionNumber, changelog);
210 224 });
211 225
226 + function formatSize(bytes) {
227 + if (bytes > 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
228 + if (bytes > 1024) return (bytes / 1024).toFixed(0) + ' KB';
229 + return bytes + ' B';
230 + }
231 +
232 + function updateQueueStatus(idx, status) {
233 + var el = document.getElementById('queue-item-' + idx);
234 + if (!el) return;
235 + var s = el.querySelector('.queue-status');
236 + if (status === 'uploading') { s.textContent = '...'; s.style.opacity = '1'; }
237 + else if (status === 'done') { s.textContent = 'OK'; s.style.opacity = '0.7'; el.style.opacity = '0.6'; }
238 + else if (status === 'error') { s.textContent = '!'; s.style.color = 'var(--error, #c0392b)'; s.style.opacity = '1'; }
239 + }
240 +
212 241 function uploadSequentially(entries, i, versionNumber, changelog) {
213 242 if (i >= entries.length) {
214 243 document.getElementById('version-upload-progress').classList.add('hidden');
@@ -224,6 +253,7 @@
224 253 var labelInput = document.querySelector('.version-label-input[data-idx="' + entry.idx + '"]');
225 254 var label = labelInput ? labelInput.value.trim() : '';
226 255
256 + updateQueueStatus(entry.idx, 'uploading');
227 257 uploader.filenameEl.textContent = entry.file.name + (entries.length > 1 ? ' (' + (i + 1) + '/' + entries.length + ')' : '');
228 258
229 259 fetch('/api/items/' + itemId + '/versions', {
@@ -275,9 +305,13 @@
275 305 if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
276 306 throw new Error(d.error || 'Failed to confirm upload');
277 307 });
308 + updateQueueStatus(entry.idx, 'done');
278 309 uploadSequentially(entries, i + 1, versionNumber, changelog);
279 310 })
280 - .catch(function(err) { showVersionError(err.message || 'Upload failed'); });
311 + .catch(function(err) {
312 + updateQueueStatus(entry.idx, 'error');
313 + showVersionError(err.message || 'Upload failed');
314 + });
281 315 }
282 316
283 317 // Existing version upload (single file)
@@ -122,8 +122,8 @@
122 122 {% endblock %}
123 123
124 124 {% block scripts %}
125 - <script src="/static/upload.js?v=0516"></script>
126 - <script src="/static/media-picker.js?v=0516"></script>
127 - <script src="/static/item-details.js?v=0516"></script>
128 - <script src="/static/item-upload.js?v=0516"></script>
125 + <script src="/static/upload.js?v=0517"></script>
126 + <script src="/static/media-picker.js?v=0517"></script>
127 + <script src="/static/item-details.js?v=0517"></script>
128 + <script src="/static/item-upload.js?v=0517"></script>
129 129 {% endblock %}
@@ -92,6 +92,7 @@
92 92
93 93 <!-- Shared upload progress/status (outside both forms so always visible) -->
94 94 <div class="upload-progress hidden" id="version-upload-progress">
95 + <div id="version-upload-queue" style="margin-bottom: 0.75rem;"></div>
95 96 <div class="progress-info">
96 97 <span id="version-upload-filename">filename.zip</span>
97 98 <span id="version-upload-percent">0%</span>