From 6180f9abb19377e8f6b92396a2f4a184699c38fb Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sat, 28 Feb 2026 10:53:41 +0100 Subject: [PATCH] refactor: convert library scan to Server Action - Add src/app/actions/library.ts with scanLibrary - Update ScanButton to use Server Action - Remove POST from api/komga/libraries/[libraryId]/scan route --- docs/server-actions-plan.md | 1 + src/app/actions/library.ts | 28 ++++++++++++ .../komga/libraries/[libraryId]/scan/route.ts | 45 ------------------- src/components/library/ScanButton.tsx | 18 +++----- 4 files changed, 35 insertions(+), 57 deletions(-) create mode 100644 src/app/actions/library.ts delete mode 100644 src/app/api/komga/libraries/[libraryId]/scan/route.ts diff --git a/docs/server-actions-plan.md b/docs/server-actions-plan.md index 49d8d1b..6f7cad2 100644 --- a/docs/server-actions-plan.md +++ b/docs/server-actions-plan.md @@ -11,6 +11,7 @@ | `POST /api/komga/favorites` | `addToFavorites()` | ✅ Done | | `DELETE /api/komga/favorites` | `removeFromFavorites()` | ✅ Done | | `PUT /api/preferences` | `updatePreferences()` | ✅ Done | +| `POST /api/komga/libraries/[libraryId]/scan` | `scanLibrary()` | ✅ Done | --- diff --git a/src/app/actions/library.ts b/src/app/actions/library.ts new file mode 100644 index 0000000..baa8e25 --- /dev/null +++ b/src/app/actions/library.ts @@ -0,0 +1,28 @@ +"use server"; + +import { revalidatePath } from "next/cache"; +import { LibraryService } from "@/lib/services/library.service"; +import { ERROR_CODES } from "@/constants/errorCodes"; +import { AppError } from "@/utils/errors"; + +/** + * Lance un scan de bibliothèque + */ +export async function scanLibrary( + libraryId: string +): Promise<{ success: boolean; message: string }> { + try { + await LibraryService.scanLibrary(libraryId, false); + + // Invalider le cache de la bibliothèque + revalidatePath(`/libraries/${libraryId}`); + revalidatePath("/libraries"); + + return { success: true, message: "Scan lancé" }; + } catch (error) { + if (error instanceof AppError) { + return { success: false, message: error.message }; + } + return { success: false, message: "Erreur lors du scan" }; + } +} diff --git a/src/app/api/komga/libraries/[libraryId]/scan/route.ts b/src/app/api/komga/libraries/[libraryId]/scan/route.ts deleted file mode 100644 index b5bef3a..0000000 --- a/src/app/api/komga/libraries/[libraryId]/scan/route.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { NextResponse } from "next/server"; -import { LibraryService } from "@/lib/services/library.service"; -import { ERROR_CODES } from "@/constants/errorCodes"; -import { AppError } from "@/utils/errors"; -import { getErrorMessage } from "@/utils/errors"; -import type { NextRequest } from "next/server"; -import logger from "@/lib/logger"; - -export async function POST( - request: NextRequest, - { params }: { params: Promise<{ libraryId: string }> } -) { - try { - const libraryId: string = (await params).libraryId; - - // Scan library with deep=false - await LibraryService.scanLibrary(libraryId, false); - - return NextResponse.json({ success: true }); - } catch (error) { - logger.error({ err: error }, "API Library Scan - Erreur"); - if (error instanceof AppError) { - return NextResponse.json( - { - error: { - code: error.code, - name: "Library scan error", - message: getErrorMessage(error.code), - }, - }, - { status: 500 } - ); - } - return NextResponse.json( - { - error: { - code: ERROR_CODES.LIBRARY.SCAN_ERROR, - name: "Library scan error", - message: getErrorMessage(ERROR_CODES.LIBRARY.SCAN_ERROR), - }, - }, - { status: 500 } - ); - } -} diff --git a/src/components/library/ScanButton.tsx b/src/components/library/ScanButton.tsx index 88b0435..70bb270 100644 --- a/src/components/library/ScanButton.tsx +++ b/src/components/library/ScanButton.tsx @@ -8,6 +8,7 @@ import { cn } from "@/lib/utils"; import { useTranslation } from "react-i18next"; import { useRouter } from "next/navigation"; import logger from "@/lib/logger"; +import { scanLibrary } from "@/app/actions/library"; interface ScanButtonProps { libraryId: string; @@ -22,12 +23,10 @@ export function ScanButton({ libraryId }: ScanButtonProps) { const handleScan = async () => { setIsScanning(true); try { - const response = await fetch(`/api/komga/libraries/${libraryId}/scan`, { - method: "POST", - }); + const result = await scanLibrary(libraryId); - if (!response.ok) { - throw new Error("Failed to scan library"); + if (!result.success) { + throw new Error(result.message); } toast({ @@ -35,14 +34,9 @@ export function ScanButton({ libraryId }: ScanButtonProps) { description: t("library.scan.success.description"), }); - // Attendre 5 secondes pour que le scan se termine, puis invalider le cache et rafraîchir + // Attendre 5 secondes pour que le scan se termine, puis rafraîchir setTimeout(async () => { try { - // Invalider le cache - await fetch(`/api/komga/libraries/${libraryId}/series`, { - method: "DELETE", - }); - // Rafraîchir la page pour voir les changements router.refresh(); @@ -52,7 +46,7 @@ export function ScanButton({ libraryId }: ScanButtonProps) { description: t("library.scan.complete.description"), }); } catch (error) { - logger.error({ err: error }, "Error invalidating cache after scan:"); + logger.error({ err: error }, "Error refreshing after scan:"); toast({ variant: "destructive", title: t("library.scan.error.title"),