diff --git a/renderer/app.js b/renderer/app.js index d08f847..0795b0b 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -1019,6 +1019,25 @@ function showContextMenu(x, y) { cancelSep.style.display = 'none'; } + // Dynamic "delete by hoster" submenu + const deleteHosterSubmenu = menu.querySelector('.ctx-hoster-delete-submenu'); + const deleteHosterContainer = menu.querySelector('.ctx-hoster-delete-items'); + const hosterCounts = new Map(); + queueJobs.forEach(j => hosterCounts.set(j.hoster, (hosterCounts.get(j.hoster) || 0) + 1)); + deleteHosterContainer.innerHTML = ''; + if (hosterCounts.size > 0) { + deleteHosterSubmenu.style.display = ''; + hosterCounts.forEach((count, hoster) => { + const item = document.createElement('div'); + item.className = 'ctx-item ctx-item-danger'; + item.dataset.action = `delete-hoster:${hoster}`; + item.textContent = `${getHosterLabel(hoster)} (${count})`; + deleteHosterContainer.appendChild(item); + }); + } else { + deleteHosterSubmenu.style.display = 'none'; + } + menu.style.display = 'block'; const menuX = Math.min(x, window.innerWidth - menu.offsetWidth - 5); menu.style.left = menuX + 'px'; @@ -1026,7 +1045,12 @@ function showContextMenu(x, y) { // Flip submenus if they would overflow the viewport right edge menu.querySelectorAll('.ctx-submenu-items').forEach(sub => { + // Temporarily show to measure actual width (display:none → offsetWidth=0) + sub.style.visibility = 'hidden'; + sub.style.display = 'block'; sub.classList.toggle('flip-left', menuX + menu.offsetWidth + sub.offsetWidth > window.innerWidth); + sub.style.display = ''; + sub.style.visibility = ''; }); } @@ -1252,6 +1276,25 @@ async function handleContextAction(action) { renderQueueTable(); updateStatusBar(); updateQueueActionButtons(); + } else if (action.startsWith('delete-hoster:')) { + const hoster = action.replace('delete-hoster:', ''); + // Cancel active uploads for this hoster + const activeIds = queueJobs + .filter(j => j.hoster === hoster && (j.status === 'uploading' || j.status === 'queued' || j.status === 'retrying' || j.status === 'getting-server' || j.status === 'preview')) + .map(j => j.id); + if (activeIds.length > 0) await window.api.cancelSelectedJobs(activeIds); + // Remove ALL jobs for this hoster + queueJobs = queueJobs.filter(j => { + if (j.hoster === hoster) { removeJobFromIndex(j); return false; } + return true; + }); + selectedJobIds.clear(); + syncSelectedFilesFromQueue(); + renderQueueTable(); + if (queueJobs.length === 0) { selectedFiles = []; updateUploadView(); } + updateStatusBar(); + updateQueueActionButtons(); + persistQueueStateSoon(true); } else if (action.startsWith('shutdown-')) { const mode = action.replace('shutdown-', ''); await window.api.setShutdownAfterFinish(mode); diff --git a/renderer/index.html b/renderer/index.html index 157d622..91c5c3b 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -265,6 +265,10 @@