From fe54f55f474e9deee25654753ae6fd6c4b30e76a Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Fri, 13 Mar 2026 13:44:48 +0100 Subject: [PATCH] feat(indexer,backoffice): ajouter warnings dans les stats de job, skip fichiers inaccessibles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Indexer: ajout du champ `warnings` dans JobStats pour les erreurs non-fatales (fichiers inaccessibles, permissions) - Indexer: skip les fichiers dont le stat échoue au lieu de faire crasher tout le scan de la library - Backoffice: affichage des warnings dans le détail job (summary, timeline, Index Statistics) et dans la popin jobs Co-Authored-By: Claude Opus 4.6 --- apps/backoffice/app/components/JobsIndicator.tsx | 6 +++++- apps/backoffice/app/jobs/[id]/page.tsx | 6 +++++- apps/backoffice/lib/api.ts | 1 + apps/indexer/src/job.rs | 1 + apps/indexer/src/scanner.rs | 13 ++++++++++--- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/backoffice/app/components/JobsIndicator.tsx b/apps/backoffice/app/components/JobsIndicator.tsx index 992bceb..05a2fab 100644 --- a/apps/backoffice/app/components/JobsIndicator.tsx +++ b/apps/backoffice/app/components/JobsIndicator.tsx @@ -19,6 +19,7 @@ interface Job { scanned_files: number; indexed_files: number; errors: number; + warnings: number; } | null; } @@ -261,8 +262,11 @@ export function JobsIndicator() { {job.stats_json && (
✓ {job.stats_json.indexed_files} + {(job.stats_json.warnings ?? 0) > 0 && ( + ⚠ {job.stats_json.warnings} + )} {job.stats_json.errors > 0 && ( - ⚠ {job.stats_json.errors} + ✕ {job.stats_json.errors} )}
)} diff --git a/apps/backoffice/app/jobs/[id]/page.tsx b/apps/backoffice/app/jobs/[id]/page.tsx index 4d8a0fa..8c57877 100644 --- a/apps/backoffice/app/jobs/[id]/page.tsx +++ b/apps/backoffice/app/jobs/[id]/page.tsx @@ -30,6 +30,7 @@ interface JobDetails { indexed_files: number; removed_files: number; errors: number; + warnings: number; } | null; error_opt: string | null; } @@ -182,6 +183,7 @@ export default async function JobDetailPage({ params }: JobDetailPageProps) { — {job.stats_json.scanned_files} scanned, {job.stats_json.indexed_files} indexed {job.stats_json.removed_files > 0 && `, ${job.stats_json.removed_files} removed`} + {(job.stats_json.warnings ?? 0) > 0 && `, ${job.stats_json.warnings} warnings`} {job.stats_json.errors > 0 && `, ${job.stats_json.errors} errors`} {job.total_files != null && job.total_files > 0 && `, ${job.total_files} thumbnails`} @@ -312,6 +314,7 @@ export default async function JobDetailPage({ params }: JobDetailPageProps) { · {job.stats_json.scanned_files} scanned, {job.stats_json.indexed_files} indexed {job.stats_json.removed_files > 0 && `, ${job.stats_json.removed_files} removed`} + {(job.stats_json.warnings ?? 0) > 0 && `, ${job.stats_json.warnings} warn`} )}

@@ -462,10 +465,11 @@ export default async function JobDetailPage({ params }: JobDetailPageProps) { )} -
+
+ 0 ? "warning" : "default"} /> 0 ? "error" : "default"} />
diff --git a/apps/backoffice/lib/api.ts b/apps/backoffice/lib/api.ts index eb66d27..5358f09 100644 --- a/apps/backoffice/lib/api.ts +++ b/apps/backoffice/lib/api.ts @@ -25,6 +25,7 @@ export type IndexJobDto = { indexed_files: number; removed_files: number; errors: number; + warnings: number; } | null; progress_percent: number | null; processed_files: number | null; diff --git a/apps/indexer/src/job.rs b/apps/indexer/src/job.rs index 2096d8f..eea13e7 100644 --- a/apps/indexer/src/job.rs +++ b/apps/indexer/src/job.rs @@ -292,6 +292,7 @@ pub async fn process_job( indexed_files: 0, removed_files: 0, errors: 0, + warnings: 0, }; let mut total_processed_count = 0i32; diff --git a/apps/indexer/src/scanner.rs b/apps/indexer/src/scanner.rs index 3c15735..979206a 100644 --- a/apps/indexer/src/scanner.rs +++ b/apps/indexer/src/scanner.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::Result; use chrono::{DateTime, Utc}; use parsers::{detect_format, parse_metadata_fast}; use serde::Serialize; @@ -21,6 +21,7 @@ pub struct JobStats { pub indexed_files: usize, pub removed_files: usize, pub errors: usize, + pub warnings: usize, } const BATCH_SIZE: usize = 100; @@ -205,8 +206,14 @@ pub async fn scan_library_discovery( .map(|s| s.to_string_lossy().to_string()) .unwrap_or_else(|| abs_path.clone()); - let metadata = std::fs::metadata(&path) - .with_context(|| format!("cannot stat {}", path.display()))?; + let metadata = match std::fs::metadata(&path) { + Ok(m) => m, + Err(e) => { + warn!("[SCAN] cannot stat {}, skipping: {}", path.display(), e); + stats.warnings += 1; + continue; + } + }; let mtime: DateTime = metadata .modified() .map(DateTime::::from)