feat: add batch metadata jobs, series filters, and translate backoffice to French
- Add metadata_batch job type with background processing via tokio::spawn - Auto-apply metadata only when single result at 100% confidence - Support primary + fallback provider per library, "none" to opt out - Add batch report/results API endpoints and job detail UI - Add series_status and has_missing filters to both series listing pages - Add GET /series/statuses endpoint for dynamic filter options - Normalize series_metadata status values (migration 0036) - Hide ComicVine provider tab when no API key configured - Translate entire backoffice UI from English to French Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -152,7 +152,7 @@ export function JobsIndicator() {
|
||||
hover:bg-accent
|
||||
transition-colors duration-200
|
||||
"
|
||||
title="View all jobs"
|
||||
title="Voir toutes les tâches"
|
||||
>
|
||||
<JobsIcon className="w-[18px] h-[18px]" />
|
||||
</Link>
|
||||
@@ -187,11 +187,11 @@ export function JobsIndicator() {
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xl">📊</span>
|
||||
<div>
|
||||
<h3 className="font-semibold text-foreground">Active Jobs</h3>
|
||||
<h3 className="font-semibold text-foreground">Tâches actives</h3>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{runningJobs.length > 0
|
||||
? `${runningJobs.length} running, ${pendingJobs.length} pending`
|
||||
: `${pendingJobs.length} job${pendingJobs.length !== 1 ? 's' : ''} pending`
|
||||
? `${runningJobs.length} en cours, ${pendingJobs.length} en attente`
|
||||
: `${pendingJobs.length} tâche${pendingJobs.length !== 1 ? 's' : ''} en attente`
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
@@ -201,7 +201,7 @@ export function JobsIndicator() {
|
||||
className="text-sm font-medium text-primary hover:text-primary/80 transition-colors"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
View All →
|
||||
Tout voir →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -209,7 +209,7 @@ export function JobsIndicator() {
|
||||
{runningJobs.length > 0 && (
|
||||
<div className="px-4 py-3 border-b border-border/60">
|
||||
<div className="flex items-center justify-between text-sm mb-2">
|
||||
<span className="text-muted-foreground">Overall Progress</span>
|
||||
<span className="text-muted-foreground">Progression globale</span>
|
||||
<span className="font-semibold text-foreground">{Math.round(totalProgress)}%</span>
|
||||
</div>
|
||||
<ProgressBar value={totalProgress} size="sm" variant="success" />
|
||||
@@ -221,7 +221,7 @@ export function JobsIndicator() {
|
||||
{activeJobs.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center py-8 text-muted-foreground">
|
||||
<span className="text-4xl mb-2">✅</span>
|
||||
<p>No active jobs</p>
|
||||
<p>Aucune tâche active</p>
|
||||
</div>
|
||||
) : (
|
||||
<ul className="divide-y divide-border/60">
|
||||
@@ -242,7 +242,7 @@ export function JobsIndicator() {
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<code className="text-xs px-1.5 py-0.5 bg-muted rounded font-mono">{job.id.slice(0, 8)}</code>
|
||||
<Badge variant={job.type === 'rebuild' ? 'primary' : job.type === 'thumbnail_regenerate' ? 'warning' : 'secondary'} className="text-[10px]">
|
||||
{job.type === 'thumbnail_rebuild' ? 'Thumbnails' : job.type === 'thumbnail_regenerate' ? 'Regenerate' : job.type}
|
||||
{job.type === 'thumbnail_rebuild' ? 'Miniatures' : job.type === 'thumbnail_regenerate' ? 'Regénération' : job.type}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
@@ -281,7 +281,7 @@ export function JobsIndicator() {
|
||||
|
||||
{/* Footer */}
|
||||
<div className="px-4 py-2 border-t border-border/60 bg-muted/50">
|
||||
<p className="text-xs text-muted-foreground text-center">Auto-refreshing every 2s</p>
|
||||
<p className="text-xs text-muted-foreground text-center">Actualisation automatique toutes les 2s</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
@@ -304,7 +304,7 @@ export function JobsIndicator() {
|
||||
${isOpen ? 'ring-2 ring-ring ring-offset-2 ring-offset-background' : ''}
|
||||
`}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
title={`${totalCount} active job${totalCount !== 1 ? 's' : ''}`}
|
||||
title={`${totalCount} tâche${totalCount !== 1 ? 's' : ''} active${totalCount !== 1 ? 's' : ''}`}
|
||||
>
|
||||
{/* Animated spinner for running jobs */}
|
||||
{runningJobs.length > 0 && (
|
||||
|
||||
Reference in New Issue
Block a user