From 98d0f1c9c5e50aa5620ff4366b6ede10023d0522 Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Fri, 27 Mar 2026 10:41:31 +0100 Subject: [PATCH] feat: bloc About avec versions dans les settings - Endpoint GET /version (sans auth) retournant la version API - Bloc About dans l'onglet General : nom du projet, description, versions API et Backoffice, lien GitHub Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/api/src/handlers.rs | 6 +++ apps/api/src/main.rs | 1 + .../app/(app)/settings/SettingsPage.tsx | 54 ++++++++++++++++++- apps/backoffice/app/(app)/settings/page.tsx | 10 +++- apps/backoffice/lib/i18n/en.ts | 4 ++ apps/backoffice/lib/i18n/fr.ts | 4 ++ 6 files changed, 77 insertions(+), 2 deletions(-) diff --git a/apps/api/src/handlers.rs b/apps/api/src/handlers.rs index 26cb73c..3795eca 100644 --- a/apps/api/src/handlers.rs +++ b/apps/api/src/handlers.rs @@ -7,6 +7,12 @@ pub async fn health() -> &'static str { "ok" } +pub async fn version() -> Json { + Json(serde_json::json!({ + "api": env!("CARGO_PKG_VERSION"), + })) +} + pub async fn docs_redirect() -> impl axum::response::IntoResponse { axum::response::Redirect::to("/swagger-ui/") } diff --git a/apps/api/src/main.rs b/apps/api/src/main.rs index 06090d7..c80af8d 100644 --- a/apps/api/src/main.rs +++ b/apps/api/src/main.rs @@ -199,6 +199,7 @@ async fn main() -> anyhow::Result<()> { let app = Router::new() .route("/health", get(handlers::health)) + .route("/version", get(handlers::version)) .route("/ready", get(handlers::ready)) .route("/metrics", get(handlers::metrics)) .route("/docs", get(handlers::docs_redirect)) diff --git a/apps/backoffice/app/(app)/settings/SettingsPage.tsx b/apps/backoffice/app/(app)/settings/SettingsPage.tsx index fab7819..389213a 100644 --- a/apps/backoffice/app/(app)/settings/SettingsPage.tsx +++ b/apps/backoffice/app/(app)/settings/SettingsPage.tsx @@ -30,9 +30,10 @@ interface SettingsPageProps { initialStatusMappings: Record[]; initialSeriesStatuses: string[]; initialProviderStatuses: string[]; + versions?: { api: string; backoffice: string }; } -export default function SettingsPage({ initialSettings, initialCacheStats, initialThumbnailStats, users, initialTab, initialProwlarr, initialQbittorrent, initialTorrentImport, initialTelegram, initialAnilist, initialKomga, initialMetadataProviders, initialStatusMappings, initialSeriesStatuses, initialProviderStatuses }: SettingsPageProps) { +export default function SettingsPage({ initialSettings, initialCacheStats, initialThumbnailStats, users, initialTab, initialProwlarr, initialQbittorrent, initialTorrentImport, initialTelegram, initialAnilist, initialKomga, initialMetadataProviders, initialStatusMappings, initialSeriesStatuses, initialProviderStatuses, versions }: SettingsPageProps) { const { t, locale, setLocale } = useTranslation(); const router = useRouter(); const searchParams = useSearchParams(); @@ -527,6 +528,57 @@ export default function SettingsPage({ initialSettings, initialCacheStats, initi + {/* About */} + + + + + {t("settings.about")} + + + +
+
+

Stripstream Librarian

+

{t("settings.aboutDesc")}

+
+ +
+
+
+ +
+
+

API

+

{versions?.api ?? "?"}

+
+
+
+
+ +
+
+

Backoffice

+

{versions?.backoffice ?? "?"}

+
+
+
+ + +
+
+
+ )} {activeTab === "metadata" && (<> diff --git a/apps/backoffice/app/(app)/settings/page.tsx b/apps/backoffice/app/(app)/settings/page.tsx index f28fc45..7fc30ac 100644 --- a/apps/backoffice/app/(app)/settings/page.tsx +++ b/apps/backoffice/app/(app)/settings/page.tsx @@ -1,11 +1,12 @@ import { getSettings, getCacheStats, getThumbnailStats, fetchUsers, apiFetch } from "@/lib/api"; import SettingsPage from "./SettingsPage"; +import packageJson from "../../../package.json"; export const dynamic = "force-dynamic"; export default async function SettingsPageWrapper({ searchParams }: { searchParams: Promise<{ tab?: string }> }) { const { tab } = await searchParams; - const [settings, cacheStats, thumbnailStats, users, prowlarr, qbittorrent, torrentImport, telegram, anilist, komga, metadataProviders, statusMappings, seriesStatuses, providerStatuses] = await Promise.all([ + const [settings, cacheStats, thumbnailStats, users, prowlarr, qbittorrent, torrentImport, telegram, anilist, komga, metadataProviders, statusMappings, seriesStatuses, providerStatuses, apiVersion] = await Promise.all([ getSettings().catch(() => ({ image_processing: { format: "webp", quality: 85, filter: "lanczos3", max_width: 2160 }, cache: { enabled: true, directory: "/tmp/stripstream-image-cache", max_size_mb: 10000 }, @@ -25,8 +26,14 @@ export default async function SettingsPageWrapper({ searchParams }: { searchPara apiFetch("/settings/status-mappings").catch(() => []), apiFetch("/series/statuses").catch(() => []), apiFetch("/series/provider-statuses").catch(() => []), + apiFetch<{ api?: string }>("/version").catch(() => ({ api: "?" })), ]); + const versions = { + api: apiVersion?.api ?? "?", + backoffice: packageJson.version, + }; + return ( []} initialSeriesStatuses={seriesStatuses as string[]} initialProviderStatuses={providerStatuses as string[]} + versions={versions} /> ); } diff --git a/apps/backoffice/lib/i18n/en.ts b/apps/backoffice/lib/i18n/en.ts index ced7a43..732c05f 100644 --- a/apps/backoffice/lib/i18n/en.ts +++ b/apps/backoffice/lib/i18n/en.ts @@ -554,6 +554,10 @@ const en: Record = { "settings.totalSize": "Total size", "settings.thumbnailsNote": "Note: Thumbnail settings are used during indexing. Existing thumbnails will not be automatically regenerated. Thumbnail generation concurrency is controlled by the \"Concurrent renders\" setting in Performance limits above.", + // Settings - About + "settings.about": "About", + "settings.aboutDesc": "Comic book and ebook library manager. Automatic indexing, metadata from multiple providers, integrated search and download, reading tracking.", + // Settings - Komga "settings.komgaSync": "Komga sync", "settings.komgaDesc": "Import reading status from a Komga server. Books are matched by title (case-insensitive). Credentials are not stored.", diff --git a/apps/backoffice/lib/i18n/fr.ts b/apps/backoffice/lib/i18n/fr.ts index 5b0018d..47bf8e2 100644 --- a/apps/backoffice/lib/i18n/fr.ts +++ b/apps/backoffice/lib/i18n/fr.ts @@ -552,6 +552,10 @@ const fr = { "settings.totalSize": "Taille totale", "settings.thumbnailsNote": "Note : Les paramètres des miniatures sont utilisés pendant l'indexation. Les miniatures existantes ne seront pas regénérées automatiquement. La concurrence de génération des miniatures est contrôlée par le paramètre « Rendus simultanés » dans les Limites de performance ci-dessus.", + // Settings - About + "settings.about": "A propos", + "settings.aboutDesc": "Gestionnaire de bibliothèque de bandes dessinées et ebooks. Indexation automatique, métadonnées depuis plusieurs fournisseurs, recherche et téléchargement intégrés, suivi de lecture.", + // Settings - Komga "settings.komgaSync": "Synchronisation Komga", "settings.komgaDesc": "Importer le statut de lecture depuis un serveur Komga. Les livres sont associés par titre (insensible à la casse). Les identifiants ne sont pas stockés.",