mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-03-28 03:29:25 +01:00
fix(downloads): allow users to dismiss failed downloads
Failed download jobs persist in BullMQ forever with no way to clear them, leaving stale error notifications in Content Explorer and Easy Setup. Adds a dismiss button (X) on failed download cards that removes the job from the queue via a new DELETE endpoint. - Backend: DELETE /api/downloads/jobs/:jobId endpoint - Frontend: X button on failed download cards with immediate refresh Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bf9260f7af
commit
608206f77f
|
|
@ -15,4 +15,9 @@ export default class DownloadsController {
|
|||
const payload = await request.validateUsing(downloadJobsByFiletypeSchema)
|
||||
return this.downloadService.listDownloadJobs(payload.params.filetype)
|
||||
}
|
||||
|
||||
async removeJob({ params }: HttpContext) {
|
||||
await this.downloadService.removeFailedJob(params.jobId)
|
||||
return { success: true }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,4 +50,15 @@ export class DownloadService {
|
|||
return b.progress - a.progress
|
||||
})
|
||||
}
|
||||
|
||||
async removeFailedJob(jobId: string): Promise<void> {
|
||||
for (const queueName of [RunDownloadJob.queue, DownloadModelJob.queue]) {
|
||||
const queue = this.queueService.getQueue(queueName)
|
||||
const job = await queue.getJob(jobId)
|
||||
if (job) {
|
||||
await job.remove()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import useDownloads, { useDownloadsProps } from '~/hooks/useDownloads'
|
|||
import HorizontalBarChart from './HorizontalBarChart'
|
||||
import { extractFileName } from '~/lib/util'
|
||||
import StyledSectionHeader from './StyledSectionHeader'
|
||||
import { IconAlertTriangle } from '@tabler/icons-react'
|
||||
import { IconAlertTriangle, IconX } from '@tabler/icons-react'
|
||||
import api from '~/lib/api'
|
||||
|
||||
interface ActiveDownloadProps {
|
||||
filetype?: useDownloadsProps['filetype']
|
||||
|
|
@ -10,7 +11,12 @@ interface ActiveDownloadProps {
|
|||
}
|
||||
|
||||
const ActiveDownloads = ({ filetype, withHeader = false }: ActiveDownloadProps) => {
|
||||
const { data: downloads } = useDownloads({ filetype })
|
||||
const { data: downloads, invalidate } = useDownloads({ filetype })
|
||||
|
||||
const handleDismiss = async (jobId: string) => {
|
||||
await api.removeDownloadJob(jobId)
|
||||
invalidate()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -37,6 +43,13 @@ const ActiveDownloads = ({ filetype, withHeader = false }: ActiveDownloadProps)
|
|||
Download failed{download.failedReason ? `: ${download.failedReason}` : ''}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleDismiss(download.jobId)}
|
||||
className="flex-shrink-0 p-1 rounded hover:bg-red-100 transition-colors"
|
||||
title="Dismiss failed download"
|
||||
>
|
||||
<IconX className="w-4 h-4 text-red-400 hover:text-red-600" />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<HorizontalBarChart
|
||||
|
|
|
|||
|
|
@ -532,6 +532,12 @@ class API {
|
|||
})()
|
||||
}
|
||||
|
||||
async removeDownloadJob(jobId: string): Promise<void> {
|
||||
return catchInternal(async () => {
|
||||
await this.client.delete(`/downloads/jobs/${jobId}`)
|
||||
})()
|
||||
}
|
||||
|
||||
async runBenchmark(type: BenchmarkType, sync: boolean = false) {
|
||||
return catchInternal(async () => {
|
||||
const response = await this.client.post<RunBenchmarkResponse>(
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ router
|
|||
.group(() => {
|
||||
router.get('/jobs', [DownloadsController, 'index'])
|
||||
router.get('/jobs/:filetype', [DownloadsController, 'filetype'])
|
||||
router.delete('/jobs/:jobId', [DownloadsController, 'removeJob'])
|
||||
})
|
||||
.prefix('/api/downloads')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user