From c20240be82ad80e499ac75084863896568d2cf11 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Sun, 28 Sep 2025 13:43:00 -0600 Subject: [PATCH] Add advanced menu on job to allow user to do things like make a job as stopped if the status ever gets hung --- .../api/jobs/[jobID]/mark_stopped/route.ts | 26 +++++++++++++++ ui/src/components/JobActionBar.tsx | 33 +++++++++++++++++-- ui/src/utils/jobs.ts | 16 +++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 ui/src/app/api/jobs/[jobID]/mark_stopped/route.ts diff --git a/ui/src/app/api/jobs/[jobID]/mark_stopped/route.ts b/ui/src/app/api/jobs/[jobID]/mark_stopped/route.ts new file mode 100644 index 00000000..705c3699 --- /dev/null +++ b/ui/src/app/api/jobs/[jobID]/mark_stopped/route.ts @@ -0,0 +1,26 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export async function GET(request: NextRequest, { params }: { params: { jobID: string } }) { + const { jobID } = await params; + + const job = await prisma.job.findUnique({ + where: { id: jobID }, + }); + + // update job status to 'running' + await prisma.job.update({ + where: { id: jobID }, + data: { + stop: true, + status: 'stopped', + info: 'Job stopped', + }, + }); + + console.log(`Job ${jobID} marked as stopped`); + + return NextResponse.json(job); +} diff --git a/ui/src/components/JobActionBar.tsx b/ui/src/components/JobActionBar.tsx index 4c4c910b..0106a393 100644 --- a/ui/src/components/JobActionBar.tsx +++ b/ui/src/components/JobActionBar.tsx @@ -1,9 +1,10 @@ import Link from 'next/link'; -import { Eye, Trash2, Pen, Play, Pause } from 'lucide-react'; +import { Eye, Trash2, Pen, Play, Pause, Cog, NotebookPen } from 'lucide-react'; import { Button } from '@headlessui/react'; import { openConfirm } from '@/components/ConfirmModal'; import { Job } from '@prisma/client'; -import { startJob, stopJob, deleteJob, getAvaliableJobActions } from '@/utils/jobs'; +import { startJob, stopJob, deleteJob, getAvaliableJobActions, markJobAsStopped } from '@/utils/jobs'; +import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react'; interface JobActionBarProps { job: Job; @@ -90,6 +91,34 @@ export default function JobActionBar({ job, onRefresh, afterDelete, className, h > +
+ + + + + + +
{ + let message = `Are you sure you want to mark this job as stopped? This will set the job status to 'stopped' if the status is hung. Only do this if you are 100% sure the job is stopped. This will NOT stop the job.`; + openConfirm({ + title: 'Mark Job as Stopped', + message: message, + type: 'warning', + confirmText: 'Mark as Stopped', + onConfirm: async () => { + await markJobAsStopped(job.id); + onRefresh && onRefresh(); + }, + }); + }} + > + Mark as Stopped +
+
+
+
); } diff --git a/ui/src/utils/jobs.ts b/ui/src/utils/jobs.ts index 3a74870e..ed656edc 100644 --- a/ui/src/utils/jobs.ts +++ b/ui/src/utils/jobs.ts @@ -50,6 +50,22 @@ export const deleteJob = (jobID: string) => { }); }; +export const markJobAsStopped = (jobID: string) => { + return new Promise((resolve, reject) => { + apiClient + .get(`/api/jobs/${jobID}/mark_stopped`) + .then(res => res.data) + .then(data => { + console.log('Job marked as stopped:', data); + resolve(); + }) + .catch(error => { + console.error('Error marking job as stopped:', error); + reject(error); + }); + }); +}; + export const getJobConfig = (job: Job) => { return JSON.parse(job.job_config) as JobConfig; };