diff --git a/apps/backoffice/app/components/JobsList.tsx b/apps/backoffice/app/components/JobsList.tsx
index 91a5c50..24e1074 100644
--- a/apps/backoffice/app/components/JobsList.tsx
+++ b/apps/backoffice/app/components/JobsList.tsx
@@ -4,6 +4,8 @@ import { useState, useEffect } from "react";
import { useTranslation } from "../../lib/i18n/context";
import { JobRow } from "./JobRow";
+const PAGE_SIZE = 25;
+
interface Job {
id: string;
library_id: string | null;
@@ -45,6 +47,11 @@ export function JobsList({ initialJobs, libraries, highlightJobId }: JobsListPro
const { t, locale } = useTranslation();
const [jobs, setJobs] = useState(initialJobs);
+ const initialPage = highlightJobId
+ ? Math.ceil((initialJobs.findIndex(j => j.id === highlightJobId) + 1) / PAGE_SIZE) || 1
+ : 1;
+ const [currentPage, setCurrentPage] = useState(initialPage);
+
const formatDate = (dateStr: string): string => {
const date = new Date(dateStr);
if (isNaN(date.getTime())) return dateStr;
@@ -58,10 +65,14 @@ export function JobsList({ initialJobs, libraries, highlightJobId }: JobsListPro
});
};
+ const totalPages = Math.ceil(jobs.length / PAGE_SIZE);
+ const pageStart = (currentPage - 1) * PAGE_SIZE;
+ const visibleJobs = jobs.slice(pageStart, pageStart + PAGE_SIZE);
+
// Refresh jobs list via SSE
useEffect(() => {
const eventSource = new EventSource("/api/jobs/stream");
-
+
eventSource.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
@@ -132,7 +143,7 @@ export function JobsList({ initialJobs, libraries, highlightJobId }: JobsListPro
- {jobs.map((job) => (
+ {visibleJobs.map((job) => (
+ {totalPages > 1 && (
+
+
+ {t("pagination.range", {
+ start: pageStart + 1,
+ end: Math.min(pageStart + PAGE_SIZE, jobs.length),
+ total: jobs.length,
+ })}
+
+
+
+ {Array.from({ length: totalPages }, (_, i) => i + 1)
+ .filter(p => p === 1 || p === totalPages || Math.abs(p - currentPage) <= 1)
+ .reduce<(number | "…")[]>((acc, p, i, arr) => {
+ if (i > 0 && p - (arr[i - 1] as number) > 1) acc.push("…");
+ acc.push(p);
+ return acc;
+ }, [])
+ .map((p, i) =>
+ p === "…" ? (
+ …
+ ) : (
+
+ )
+ )}
+
+
+
+ )}
);
}
diff --git a/apps/backoffice/lib/i18n/en.ts b/apps/backoffice/lib/i18n/en.ts
index a046d90..597e936 100644
--- a/apps/backoffice/lib/i18n/en.ts
+++ b/apps/backoffice/lib/i18n/en.ts
@@ -708,6 +708,8 @@ const en: Record = {
"pagination.show": "Show",
"pagination.displaying": "Displaying {{count}} items",
"pagination.range": "{{start}}-{{end}} of {{total}}",
+ "pagination.previous": "Previous",
+ "pagination.next": "Next",
// Book detail
"bookDetail.libraries": "Libraries",
diff --git a/apps/backoffice/lib/i18n/fr.ts b/apps/backoffice/lib/i18n/fr.ts
index f7ce32e..88f2100 100644
--- a/apps/backoffice/lib/i18n/fr.ts
+++ b/apps/backoffice/lib/i18n/fr.ts
@@ -706,6 +706,8 @@ const fr = {
"pagination.show": "Afficher",
"pagination.displaying": "Affichage de {{count}} éléments",
"pagination.range": "{{start}}-{{end}} sur {{total}}",
+ "pagination.previous": "Précédent",
+ "pagination.next": "Suivant",
// Book detail
"bookDetail.libraries": "Bibliothèques",