diff --git a/services/web-ui/public/screens-jobs.jsx b/services/web-ui/public/screens-jobs.jsx index 718fa2a..e023d10 100644 --- a/services/web-ui/public/screens-jobs.jsx +++ b/services/web-ui/public/screens-jobs.jsx @@ -108,6 +108,23 @@ function Jobs({ navigate }) { ).then(refresh); }, [jobs, refresh]); + // Drop every failed job from the queue. The opposite of Retry all — used + // when a batch of jobs is unrecoverable (e.g. assets that were deleted + // mid-encode) and the operator just wants the queue cleared. + const handleCancelAll = React.useCallback(() => { + const failedJobs = jobs.filter(j => j.status === 'failed'); + if (failedJobs.length === 0) return; + if (!window.confirm(`Remove all ${failedJobs.length} failed jobs from the queue?\nThis cannot be undone.`)) return; + Promise.allSettled( + failedJobs.map(j => window.ZAMPP_API.fetch('/jobs/' + j.id, { method: 'DELETE' })) + ).then(() => { + // Optimistic local drop so the UI updates the instant the modal closes, + // not 5s later on the next poll tick. + setJobs(prev => prev.filter(j => j.status !== 'failed')); + refresh(); + }); + }, [jobs, refresh]); + const counts = { all: jobs.length, running: jobs.filter(j => j.status === 'running').length, @@ -124,9 +141,14 @@ function Jobs({ navigate }) { Proxy generation, transcoding, and processing queue
{counts.failed > 0 && ( - + <> + + + )}