- |
+ |
(
+
+);
+
+const SpinnerIcon = ({ className }: { className?: string }) => (
+
+);
+
+const ChevronIcon = ({ className }: { className?: string }) => (
+
+);
+
export function JobsIndicator() {
const [activeJobs, setActiveJobs] = useState([]);
const [isOpen, setIsOpen] = useState(false);
@@ -67,13 +91,18 @@ export function JobsIndicator() {
return (
-
+
);
}
@@ -81,56 +110,61 @@ export function JobsIndicator() {
return (
- {/* Popin/Dropdown */}
+ {/* Popin/Dropdown with glassmorphism */}
{isOpen && (
-
-
+
+ {/* Header */}
+
- 📊
+ 📊
Active Jobs
-
+
{runningJobs.length > 0
? `${runningJobs.length} running, ${pendingJobs.length} pending`
: `${pendingJobs.length} job${pendingJobs.length !== 1 ? 's' : ''} pending`
@@ -149,33 +183,29 @@ export function JobsIndicator() {
{/* Overall progress bar if running */}
{runningJobs.length > 0 && (
-
+
- Overall Progress
+ Overall Progress
{Math.round(totalProgress)}%
-
+
)}
-
+ {/* Job List */}
+
{activeJobs.length === 0 ? (
-
+
) : (
-
+
{activeJobs.map(job => (
-
setIsOpen(false)}
>
@@ -186,37 +216,30 @@ export function JobsIndicator() {
- {job.id.slice(0, 8)}
-
+ {job.id.slice(0, 8)}
+
{job.type}
-
+
{job.status === "running" && job.progress_percent !== null && (
-
- {job.progress_percent}%
+
+ {job.progress_percent}%
)}
{job.current_file && (
-
+
📄 {job.current_file}
)}
{job.stats_json && (
-
+
✓ {job.stats_json.indexed_files}
{job.stats_json.errors > 0 && (
- ⚠ {job.stats_json.errors}
+ ⚠ {job.stats_json.errors}
)}
)}
@@ -230,11 +253,23 @@ export function JobsIndicator() {
{/* Footer */}
-
- Auto-refreshing every 2s
+
+ Auto-refreshing every 2s
)}
);
}
+
+// Mini progress bar for dropdown
+function MiniProgressBar({ value }: { value: number }) {
+ return (
+
+ );
+}
diff --git a/apps/backoffice/app/components/JobsList.tsx b/apps/backoffice/app/components/JobsList.tsx
index 1e977d2..704d239 100644
--- a/apps/backoffice/app/components/JobsList.tsx
+++ b/apps/backoffice/app/components/JobsList.tsx
@@ -2,7 +2,6 @@
import { useState, useEffect } from "react";
import { JobRow } from "./JobRow";
-import { MiniProgressBar } from "./ui";
interface Job {
id: string;
@@ -45,18 +44,15 @@ function formatDate(dateStr: string): string {
const now = new Date();
const diff = now.getTime() - date.getTime();
- // Less than 1 hour: show relative
if (diff < 3600000) {
const mins = Math.floor(diff / 60000);
if (mins < 1) return "Just now";
return `${mins}m ago`;
}
- // Less than 24 hours: show hours
if (diff < 86400000) {
const hours = Math.floor(diff / 3600000);
return `${hours}h ago`;
}
- // Otherwise: show date
return date.toLocaleDateString();
}
@@ -105,22 +101,22 @@ export function JobsList({ initialJobs, libraries, highlightJobId }: JobsListPro
};
return (
-
+
-
- | ID |
- Library |
- Type |
- Status |
- Files |
- Duration |
- Created |
- Actions |
+
+ | ID |
+ Library |
+ Type |
+ Status |
+ Files |
+ Duration |
+ Created |
+ Actions |
-
+
{jobs.map((job) => (
setIsOpen(!isOpen)}
- className={isOpen ? "bg-muted/10" : ""}
+ className={isOpen ? "bg-accent" : ""}
>
- ⚙️
+
{isOpen && (
- |