From 3d836ac3716cd1260fcfc7209888d7775a39c2e5 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Mon, 25 May 2026 08:21:42 -0600 Subject: [PATCH] Show active jobs in the sidebar of the ui --- ui/src/components/ActiveJobWidget.tsx | 73 +++++++++++++++++++++++++++ ui/src/components/Sidebar.tsx | 44 ++++++++-------- 2 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 ui/src/components/ActiveJobWidget.tsx diff --git a/ui/src/components/ActiveJobWidget.tsx b/ui/src/components/ActiveJobWidget.tsx new file mode 100644 index 00000000..481bfb61 --- /dev/null +++ b/ui/src/components/ActiveJobWidget.tsx @@ -0,0 +1,73 @@ +'use client'; + +import Link from 'next/link'; +import { CgSpinner } from 'react-icons/cg'; +import useJobsList from '@/hooks/useJobsList'; +import { JobConfig } from '@/types'; + +export default function ActiveJobWidget() { + const { jobs } = useJobsList({ onlyActive: true, reloadInterval: 5000 }); + + if (!jobs || jobs.length === 0) return null; + + return ( +
+
+
    + {jobs.map(job => { + let totalSteps: number | undefined; + try { + const cfg: JobConfig = JSON.parse(job.job_config); + totalSteps = cfg.config.process[0].train?.steps; + } catch { + totalSteps = undefined; + } + const isTrain = job.job_type === 'train'; + const pct = isTrain && totalSteps ? Math.min(100, (job.step / totalSteps) * 100) : 0; + const isRunning = job.status === 'running' || job.status === 'stopping'; + + let label = job.name; + if (job.job_type === 'caption') { + const splits = (job.job_ref ?? '').split(/[/\\]/); + label = splits[splits.length - 1] || job.name; + } + + let statusColor = 'text-gray-400'; + if (job.status === 'running') statusColor = 'text-blue-400'; + if (job.status === 'queued') statusColor = 'text-yellow-400'; + if (job.status === 'stopping') statusColor = 'text-orange-400'; + + return ( +
  • + +
    + {isRunning && } + {label} +
    + {isTrain && totalSteps ? ( +
    +
    +
    +
    +
    + {job.status} + + {job.step} / {totalSteps} + +
    +
    + ) : ( +
    {job.status}
    + )} + +
  • + ); + })} +
+
+
+ ); +} diff --git a/ui/src/components/Sidebar.tsx b/ui/src/components/Sidebar.tsx index 6b45b1e2..905f757d 100644 --- a/ui/src/components/Sidebar.tsx +++ b/ui/src/components/Sidebar.tsx @@ -8,6 +8,7 @@ import { FaXTwitter, FaDiscord, FaYoutube } from 'react-icons/fa6'; import { createGlobalState } from 'react-global-hooks'; import ThemeToggle from './ThemeToggle'; import ThemeLogo from './ThemeLogo'; +import ActiveJobWidget from './ActiveJobWidget'; export const mobileSidebarState = createGlobalState(false); @@ -75,29 +76,28 @@ const Sidebar = () => { ))} -
- + + - - - - Support AI-Toolkit - -
+ + + Support AI-Toolkit + {/* Social links grid */}