diff --git a/src/index.ts b/src/index.ts index 0c8de806..f7aece03 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ import { retryAll } from './routes/retryAll' import { retryJob } from './routes/retryJob' import { promoteJob } from './routes/promoteJob' import { cleanAll } from './routes/cleanAll' +import { cleanJob } from './routes/cleanJob' import { entryPoint } from './routes/index' import { BullBoardQueues } from './@types/app' @@ -31,6 +32,7 @@ router.get('/', entryPoint) router.get('/queues', wrapAsync(queuesHandler)) router.put('/queues/:queueName/retry', wrapAsync(retryAll)) router.put('/queues/:queueName/:id/retry', wrapAsync(retryJob)) +router.put('/queues/:queueName/:id/clean', wrapAsync(cleanJob)) router.put('/queues/:queueName/:id/promote', wrapAsync(promoteJob)) router.put('/queues/:queueName/clean/:queueStatus', wrapAsync(cleanAll)) diff --git a/src/routes/cleanJob.ts b/src/routes/cleanJob.ts new file mode 100644 index 00000000..e1fa4aad --- /dev/null +++ b/src/routes/cleanJob.ts @@ -0,0 +1,36 @@ +import { RequestHandler } from 'express' +import { BullBoardQueues } from '../@types/app' + +export const cleanJob: RequestHandler = async (req, res) => { + try { + const { + bullBoardQueues, + }: { bullBoardQueues: BullBoardQueues } = req.app.locals + const { queueName, id } = req.params + const { queue } = bullBoardQueues[queueName] + + if (!queue) { + return res.status(404).send({ + error: 'Queue not found', + }) + } + + const job = await queue.getJob(id) + + if (!job) { + return res.status(404).send({ + error: 'Job not found', + }) + } + + await job.remove() + + return res.sendStatus(204) + } catch (error) { + const body = { + error: 'queue error', + details: error.stack, + } + return res.status(500).send(body) + } +} diff --git a/src/ui/components/App.tsx b/src/ui/components/App.tsx index da33fac9..4d4f3c20 100644 --- a/src/ui/components/App.tsx +++ b/src/ui/components/App.tsx @@ -13,6 +13,7 @@ export const App = ({ basePath }: { basePath: string }) => { promoteJob, retryJob, retryAll, + cleanJob, cleanAllDelayed, cleanAllFailed, cleanAllCompleted, @@ -40,6 +41,7 @@ export const App = ({ basePath }: { basePath: string }) => { selectStatus={setSelectedStatuses} promoteJob={promoteJob(queue.name)} retryJob={retryJob(queue.name)} + cleanJob={cleanJob(queue.name)} retryAll={retryAll(queue.name)} cleanAllDelayed={cleanAllDelayed(queue.name)} cleanAllFailed={cleanAllFailed(queue.name)} diff --git a/src/ui/components/Job.tsx b/src/ui/components/Job.tsx index a6108600..87c6ff25 100644 --- a/src/ui/components/Job.tsx +++ b/src/ui/components/Job.tsx @@ -11,6 +11,7 @@ import { Timestamp } from './Timestamp' type FieldProps = { job: AppJob retryJob: () => Promise + cleanJob: () => Promise delayedJob: () => Promise } @@ -126,6 +127,8 @@ const fieldComponents: Record> = { retry: ({ retryJob }) => , + clean: ({ cleanJob }) => , + promote: ({ delayedJob }) => , } @@ -134,11 +137,13 @@ export const Job = ({ status, queueName, retryJob, + cleanJob, promoteJob, }: { job: AppJob status: Status queueName: string + cleanJob: (job: AppJob) => () => Promise retryJob: (job: AppJob) => () => Promise promoteJob: (job: AppJob) => () => Promise }) => { @@ -152,6 +157,7 @@ export const Job = ({ diff --git a/src/ui/components/Jobs.tsx b/src/ui/components/Jobs.tsx index 2b905221..37e87bb4 100644 --- a/src/ui/components/Jobs.tsx +++ b/src/ui/components/Jobs.tsx @@ -5,11 +5,13 @@ import { Job } from './Job' export const Jobs = ({ retryJob, + cleanJob, promoteJob, queue: { jobs, name }, status, }: { retryJob: (job: AppJob) => () => Promise + cleanJob: (job: AppJob) => () => Promise promoteJob: (job: AppJob) => () => Promise queue: AppQueue status: Status @@ -35,6 +37,7 @@ export const Jobs = ({ status={status} queueName={name} retryJob={retryJob} + cleanJob={cleanJob} promoteJob={promoteJob} /> ))} diff --git a/src/ui/components/Queue.tsx b/src/ui/components/Queue.tsx index cc9d9636..b18c3152 100644 --- a/src/ui/components/Queue.tsx +++ b/src/ui/components/Queue.tsx @@ -93,6 +93,7 @@ interface QueueProps { cleanAllCompleted: () => Promise retryAll: () => Promise retryJob: (job: AppJob) => () => Promise + cleanJob: (job: AppJob) => () => Promise promoteJob: (job: AppJob) => () => Promise } @@ -107,6 +108,7 @@ export const Queue = ({ queue, retryAll, retryJob, + cleanJob, promoteJob, selectedStatus, selectStatus, @@ -137,6 +139,7 @@ export const Queue = ({ /> = { active: ['attempts', 'data', 'id', 'name', 'opts', 'progress', 'timestamps'], @@ -43,6 +44,7 @@ export const FIELDS: Record = { 'opts', 'promote', 'timestamps', + 'clean', ], failed: [ 'attempts', @@ -54,8 +56,9 @@ export const FIELDS: Record = { 'progress', 'retry', 'timestamps', + 'clean', ], latest: ['attempts', 'data', 'id', 'name', 'opts', 'progress', 'timestamps'], paused: ['attempts', 'data', 'id', 'name', 'opts', 'timestamps'], - waiting: ['data', 'id', 'name', 'opts', 'timestamps'], + waiting: ['data', 'id', 'name', 'opts', 'timestamps', 'clean'], } diff --git a/src/ui/components/hooks/useStore.ts b/src/ui/components/hooks/useStore.ts index 3db7c5f9..c1486b68 100644 --- a/src/ui/components/hooks/useStore.ts +++ b/src/ui/components/hooks/useStore.ts @@ -17,6 +17,7 @@ export interface Store { state: State promoteJob: (queueName: string) => (job: AppJob) => () => Promise retryJob: (queueName: string) => (job: AppJob) => () => Promise + cleanJob: (queueName: string) => (job: AppJob) => () => Promise retryAll: (queueName: string) => () => Promise cleanAllDelayed: (queueName: string) => () => Promise cleanAllFailed: (queueName: string) => () => Promise @@ -79,6 +80,14 @@ export const useStore = (basePath: string): Store => { }, ).then(update) + const cleanJob = (queueName: string) => (job: AppJob) => () => + fetch( + `${basePath}/queues/${encodeURIComponent(queueName)}/${job.id}/clean`, + { + method: 'put', + }, + ).then(update) + const retryAll = (queueName: string) => () => fetch(`${basePath}/queues/${encodeURIComponent(queueName)}/retry`, { method: 'put', @@ -107,6 +116,7 @@ export const useStore = (basePath: string): Store => { promoteJob, retryJob, retryAll, + cleanJob, cleanAllDelayed, cleanAllFailed, cleanAllCompleted,