From 741a4da8780106693c6156817316efcf4fe9d49b Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Thu, 19 Mar 2026 11:03:08 +0100 Subject: [PATCH] feat: redesign jobs page action bar with grouped layout Replace flat button row + separate reference card with a single card organized in 3 visual groups (Indexation, Thumbnails, Metadata). Each action is a card-like button with inline description. Destructive actions have distinct warning styling. Co-Authored-By: Claude Opus 4.6 --- apps/backoffice/app/jobs/page.tsx | 211 ++++++++++++++---------------- apps/backoffice/lib/i18n/en.ts | 10 ++ apps/backoffice/lib/i18n/fr.ts | 10 ++ 3 files changed, 118 insertions(+), 113 deletions(-) diff --git a/apps/backoffice/app/jobs/page.tsx b/apps/backoffice/app/jobs/page.tsx index 2033438..bf66e10 100644 --- a/apps/backoffice/app/jobs/page.tsx +++ b/apps/backoffice/app/jobs/page.tsx @@ -2,7 +2,7 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { listJobs, fetchLibraries, rebuildIndex, rebuildThumbnails, regenerateThumbnails, startMetadataBatch, startMetadataRefresh, IndexJobDto, LibraryDto } from "../../lib/api"; import { JobsList } from "../components/JobsList"; -import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, FormField, FormSelect, FormRow } from "../components/ui"; +import { Card, CardHeader, CardTitle, CardDescription, CardContent, FormField, FormSelect } from "../components/ui"; import { getServerTranslations } from "../../lib/i18n/server"; export const dynamic = "force-dynamic"; @@ -85,8 +85,8 @@ export default async function JobsPage({ searchParams }: { searchParams: Promise
- - +
+ {libraries.map((lib) => ( @@ -94,123 +94,108 @@ export default async function JobsPage({ searchParams }: { searchParams: Promise ))} -
-
+
+ + {/* Indexation group */} +
+
+ + - {t("jobs.rebuild")} - - -
+
+ + +
+
+ + {/* Thumbnails group */} +
+
+ - {t("jobs.generateThumbnails")} - - - - + {t("jobs.groupThumbnails")} +
+
+ + +
- - - - - {/* Job types legend */} - - - {t("jobs.referenceTitle")} - - -
-
-
- - - -
-
- {t("jobs.rebuild")} -

+ {/* Metadata group */} +

+
+ + + + {t("jobs.groupMetadata")} + ({t("jobs.requiresLibrary")}) +
+
+ + +
+
-
-
- - - -
-
- {t("jobs.fullRebuild")} -

-

-
-
-
- - - -
-
- {t("jobs.generateThumbnails")} -

-

-
-
-
- - - -
-
- {t("jobs.regenerateThumbnails")} -

-

-
-
-
- - - -
-
- {t("jobs.batchMetadata")} -

-

-
-
-
- - - -
-
- {t("jobs.refreshMetadata")} -

-

-
-
+ diff --git a/apps/backoffice/lib/i18n/en.ts b/apps/backoffice/lib/i18n/en.ts index 3338730..5445c6b 100644 --- a/apps/backoffice/lib/i18n/en.ts +++ b/apps/backoffice/lib/i18n/en.ts @@ -176,6 +176,16 @@ const en: Record = { "jobs.refreshMetadata": "Refresh metadata", "jobs.refreshMetadataDescription": "Refreshes metadata for all series already linked to an external provider. Re-downloads information from the provider and updates series and books in the database (respecting locked fields). Series without an approved link are ignored. Requires a specific library (does not work on \"All libraries\").", "jobs.referenceTitle": "Job types reference", + "jobs.groupIndexation": "Indexation", + "jobs.groupThumbnails": "Thumbnails", + "jobs.groupMetadata": "Metadata", + "jobs.requiresLibrary": "Requires a specific library", + "jobs.rebuildShort": "Scan new & modified files", + "jobs.fullRebuildShort": "Delete all & re-scan from scratch", + "jobs.generateThumbnailsShort": "Missing thumbnails only", + "jobs.regenerateThumbnailsShort": "Recreate all thumbnails", + "jobs.batchMetadataShort": "Auto-match unlinked series", + "jobs.refreshMetadataShort": "Update existing linked series", "jobs.rebuildDescription": "Incremental scan: detects files added, modified, or deleted since the last scan, indexes them, and generates missing thumbnails. Existing unmodified data is preserved. This is the most common and fastest action.", "jobs.fullRebuildDescription": "Deletes all indexed data (books, series, thumbnails) then performs a full scan from scratch. Useful if the database is out of sync or corrupted. Long and destructive operation: reading statuses and manual metadata will be lost.", "jobs.generateThumbnailsDescription": "Generates thumbnails only for books that don't have one yet. Existing thumbnails are not affected. Useful after an import or if some thumbnails are missing.", diff --git a/apps/backoffice/lib/i18n/fr.ts b/apps/backoffice/lib/i18n/fr.ts index 348ac73..ce74ffb 100644 --- a/apps/backoffice/lib/i18n/fr.ts +++ b/apps/backoffice/lib/i18n/fr.ts @@ -174,6 +174,16 @@ const fr = { "jobs.refreshMetadata": "Rafraîchir métadonnées", "jobs.refreshMetadataDescription": "Rafraîchit les métadonnées de toutes les séries déjà liées à un fournisseur externe. Re-télécharge les informations depuis le fournisseur et met à jour les séries et livres en base (en respectant les champs verrouillés). Les séries sans lien approuvé sont ignorées. Requiert une bibliothèque spécifique (ne fonctionne pas sur \u00ab Toutes les bibliothèques \u00bb).", "jobs.referenceTitle": "Référence des types de tâches", + "jobs.groupIndexation": "Indexation", + "jobs.groupThumbnails": "Miniatures", + "jobs.groupMetadata": "Métadonnées", + "jobs.requiresLibrary": "Requiert une bibliothèque spécifique", + "jobs.rebuildShort": "Scanner les fichiers nouveaux et modifiés", + "jobs.fullRebuildShort": "Tout supprimer et re-scanner depuis zéro", + "jobs.generateThumbnailsShort": "Miniatures manquantes uniquement", + "jobs.regenerateThumbnailsShort": "Recréer toutes les miniatures", + "jobs.batchMetadataShort": "Lier automatiquement les séries non liées", + "jobs.refreshMetadataShort": "Mettre à jour les séries déjà liées", "jobs.rebuildDescription": "Scan incrémental : détecte les fichiers ajoutés, modifiés ou supprimés depuis le dernier scan, les indexe et génère les miniatures manquantes. Les données existantes non modifiées sont conservées. C'est l'action la plus courante et la plus rapide.", "jobs.fullRebuildDescription": "Supprime toutes les données indexées (livres, séries, miniatures) puis effectue un scan complet depuis zéro. Utile si la base de données est désynchronisée ou corrompue. Opération longue et destructive : les statuts de lecture et les métadonnées manuelles seront perdus.", "jobs.generateThumbnailsDescription": "Génère les miniatures uniquement pour les livres qui n'en ont pas encore. Les miniatures existantes ne sont pas touchées. Utile après un import ou si certaines miniatures sont manquantes.",