feat: filter metadata refresh to ongoing series & improve job action buttons

- Metadata refresh now skips series with ended/cancelled status
- Add xs size to Button component
- Unify view/cancel button sizes (h-7) with icons (eye & cross)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-23 18:59:33 +01:00
parent b6422fbf3e
commit eab7f2e21b
3 changed files with 32 additions and 13 deletions

View File

@@ -110,9 +110,16 @@ pub async fn start_refresh(
})));
}
// Check there are approved links to refresh
// Check there are approved links to refresh (only ongoing series)
let link_count: i64 = sqlx::query_scalar(
"SELECT COUNT(*) FROM external_metadata_links WHERE library_id = $1 AND status = 'approved'",
r#"
SELECT COUNT(*) FROM external_metadata_links eml
LEFT JOIN series_metadata sm
ON sm.library_id = eml.library_id AND sm.name = eml.series_name
WHERE eml.library_id = $1
AND eml.status = 'approved'
AND COALESCE(sm.status, 'ongoing') NOT IN ('ended', 'cancelled')
"#,
)
.bind(library_id)
.fetch_one(&state.pool)
@@ -234,13 +241,17 @@ pub(crate) async fn process_metadata_refresh(
.await
.map_err(|e| e.to_string())?;
// Get all approved links for this library
// Get approved links for this library, only for ongoing series (not ended/cancelled)
let links: Vec<(Uuid, String, String, String)> = sqlx::query_as(
r#"
SELECT id, series_name, provider, external_id
FROM external_metadata_links
WHERE library_id = $1 AND status = 'approved'
ORDER BY series_name
SELECT eml.id, eml.series_name, eml.provider, eml.external_id
FROM external_metadata_links eml
LEFT JOIN series_metadata sm
ON sm.library_id = eml.library_id AND sm.name = eml.series_name
WHERE eml.library_id = $1
AND eml.status = 'approved'
AND COALESCE(sm.status, 'ongoing') NOT IN ('ended', 'cancelled')
ORDER BY eml.series_name
"#,
)
.bind(library_id)

View File

@@ -203,18 +203,25 @@ export function JobRow({ job, libraryName, highlighted, onCancel, formatDate, fo
</td>
<td className="px-4 py-3">
<div className="flex items-center gap-2">
<Link
<Link
href={`/jobs/${job.id}`}
className="inline-flex items-center px-3 py-1.5 text-xs font-medium rounded-lg bg-primary text-white hover:bg-primary/90 transition-colors"
className="inline-flex items-center justify-center gap-1.5 h-7 px-2.5 text-xs font-medium rounded-md bg-primary text-white hover:bg-primary/90 transition-colors"
>
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
{t("jobRow.view")}
</Link>
{(job.status === "pending" || job.status === "running" || job.status === "extracting_pages" || job.status === "generating_thumbnails") && (
<Button
variant="danger"
size="sm"
<Button
variant="danger"
size="xs"
onClick={() => onCancel(job.id)}
>
<svg className="w-3.5 h-3.5 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
{t("common.cancel")}
</Button>
)}

View File

@@ -14,7 +14,7 @@ type ButtonVariant =
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children: ReactNode;
variant?: ButtonVariant;
size?: "sm" | "md" | "lg";
size?: "xs" | "sm" | "md" | "lg";
}
const variantStyles: Record<ButtonVariant, string> = {
@@ -33,6 +33,7 @@ const variantStyles: Record<ButtonVariant, string> = {
};
const sizeStyles: Record<string, string> = {
xs: "h-7 px-2.5 text-xs rounded-md",
sm: "h-9 px-3 text-xs rounded-md",
md: "h-10 px-4 py-2 text-sm rounded-md",
lg: "h-11 px-8 text-base rounded-md",