Live-update queue list when upload status changes
Storage.updatePhoto() now fires a 'photo-updated' CustomEvent so the queue page refreshes immediately (300ms debounce) when the sync engine changes a photo's status, instead of waiting for the 5s poll. Also reduces background poll to 30s (just a fallback now), and revokes stale ObjectURLs on each rebuild to prevent memory leaks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -93,7 +93,14 @@ const Storage = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async updatePhoto(id, updates) {
|
async updatePhoto(id, updates) {
|
||||||
return await this.db.photos.update(id, updates);
|
const result = await this.db.photos.update(id, updates);
|
||||||
|
// Notify any listening UI (e.g. queue page) of the change
|
||||||
|
try {
|
||||||
|
window.dispatchEvent(new CustomEvent('photo-updated', {
|
||||||
|
detail: { id: id, updates: updates }
|
||||||
|
}));
|
||||||
|
} catch (e) { /* ignore if no window context */ }
|
||||||
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
async deletePhoto(id) {
|
async deletePhoto(id) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// NextSnap Service Worker
|
// NextSnap Service Worker
|
||||||
// Provides offline-first caching for the app shell
|
// Provides offline-first caching for the app shell
|
||||||
|
|
||||||
const CACHE_VERSION = 'nextsnap-v15';
|
const CACHE_VERSION = 'nextsnap-v16';
|
||||||
const APP_SHELL_CACHE = 'nextsnap-shell-v11';
|
const APP_SHELL_CACHE = 'nextsnap-shell-v12';
|
||||||
const RUNTIME_CACHE = 'nextsnap-runtime-v11';
|
const RUNTIME_CACHE = 'nextsnap-runtime-v12';
|
||||||
|
|
||||||
// Assets to cache on install
|
// Assets to cache on install
|
||||||
const APP_SHELL_ASSETS = [
|
const APP_SHELL_ASSETS = [
|
||||||
|
|||||||
@@ -411,6 +411,10 @@ async function loadQueue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emptyState.style.display = 'none';
|
emptyState.style.display = 'none';
|
||||||
|
// Revoke old ObjectURLs before rebuilding to prevent memory leaks
|
||||||
|
queueList.querySelectorAll('img[src^="blob:"]').forEach(img => {
|
||||||
|
URL.revokeObjectURL(img.src);
|
||||||
|
});
|
||||||
queueList.innerHTML = '';
|
queueList.innerHTML = '';
|
||||||
|
|
||||||
// Show active uploads first (newest first)
|
// Show active uploads first (newest first)
|
||||||
@@ -610,10 +614,23 @@ window.addEventListener('offline', () => {
|
|||||||
document.getElementById('sync-now-btn').disabled = true;
|
document.getElementById('sync-now-btn').disabled = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Refresh queue periodically
|
// Live updates: listen for photo status changes from the sync engine
|
||||||
|
let refreshTimer = null;
|
||||||
|
window.addEventListener('photo-updated', () => {
|
||||||
|
// Debounce: rapid status transitions (pending→uploading→verified)
|
||||||
|
// would otherwise trigger multiple full rebuilds
|
||||||
|
if (refreshTimer) clearTimeout(refreshTimer);
|
||||||
|
refreshTimer = setTimeout(() => {
|
||||||
|
refreshTimer = null;
|
||||||
|
loadQueue();
|
||||||
|
updateStats();
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fallback: full refresh every 30s in case events are missed
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
loadQueue();
|
loadQueue();
|
||||||
updateStats();
|
updateStats();
|
||||||
}, 5000);
|
}, 30000);
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user