From c277ceead751faacc3c9a5226229f0a9312f49d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Thu, 23 Jul 2026 15:42:15 +0000 Subject: [PATCH] jobs: split list into Running & Queued (top) and History (bottom, 70/30) Co-Authored-By: Claude Opus 4.8 --- .../Screens/Dashboard/Jobs/JobsPage.tsx | 89 +++++++++++++------ 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/src/apps/officer-web/Screens/Dashboard/Jobs/JobsPage.tsx b/src/apps/officer-web/Screens/Dashboard/Jobs/JobsPage.tsx index c215b8eb..888fd074 100644 --- a/src/apps/officer-web/Screens/Dashboard/Jobs/JobsPage.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Jobs/JobsPage.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, type ReactNode } from 'react'; import { useParams, useNavigate } from 'react-router'; import { Search, CheckCircle2, AlertCircle, Clock, Loader2, StopCircle, AlertTriangle, Inbox } from 'lucide-react'; import { WorkspaceLayout } from 'officerdev'; @@ -34,6 +34,12 @@ const StatusIcon = ({ status }: { status: JobSummary['status'] }) => { } }; +const SectionLabel = ({ children }: { children: ReactNode }) => ( +
+ {children} +
+); + // ── Left panel: the jobs list (polls so running/queued statuses stay fresh) ── const JobsListPanel = () => { const client = useClient(); @@ -59,10 +65,37 @@ const JobsListPanel = () => { }) : jobs; + // Active = running first, then the FIFO queue (oldest pending on top — next to run). History = the + // rest (already newest-first from the API). + const active = [ + ...filtered.filter((j) => j.status === 'running'), + ...filtered.filter((j) => j.status === 'pending').sort((a, b) => +new Date(a.createdAt) - +new Date(b.createdAt)), + ]; + const history = filtered.filter((j) => j.status !== 'running' && j.status !== 'pending'); + + const renderRow = (job: JobSummary) => ( + + ); + return (
-
+

Jobs

@@ -76,32 +109,34 @@ const JobsListPanel = () => {
-
- {isLoading &&
Loading…
} - {!isLoading && filtered.length === 0 && ( -
- {search ? 'No jobs match' : 'No jobs yet'} -
- )} - {filtered.map((job) => ( - - ))} -
+
+ {/* History — bottom 30% */} +
+ History +
+ {history.length === 0 ? ( +
{search ? 'No matches' : 'No finished jobs'}
+ ) : ( + history.map(renderRow) + )} +
+
+
+ )} );