feat: SSR pour toutes les cards de la page Settings
Toutes les configurations (Prowlarr, qBittorrent, Telegram, Anilist, Komga, metadata providers, status mappings) sont maintenant récupérées côté serveur dans page.tsx et passées en props aux cards. Supprime ~10 fetchs client useEffect au chargement, élimine les layout shifts et réduit le temps de rendu initial. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,9 +20,19 @@ interface SettingsPageProps {
|
||||
initialThumbnailStats: ThumbnailStats;
|
||||
users: UserDto[];
|
||||
initialTab?: string;
|
||||
initialProwlarr: Record<string, unknown> | null;
|
||||
initialQbittorrent: Record<string, unknown> | null;
|
||||
initialTorrentImport: Record<string, unknown> | null;
|
||||
initialTelegram: Record<string, unknown> | null;
|
||||
initialAnilist: Record<string, unknown> | null;
|
||||
initialKomga: Record<string, unknown> | null;
|
||||
initialMetadataProviders: Record<string, unknown> | null;
|
||||
initialStatusMappings: Record<string, unknown>[];
|
||||
initialSeriesStatuses: string[];
|
||||
initialProviderStatuses: string[];
|
||||
}
|
||||
|
||||
export default function SettingsPage({ initialSettings, initialCacheStats, initialThumbnailStats, users, initialTab }: SettingsPageProps) {
|
||||
export default function SettingsPage({ initialSettings, initialCacheStats, initialThumbnailStats, users, initialTab, initialProwlarr, initialQbittorrent, initialTorrentImport, initialTelegram, initialAnilist, initialKomga, initialMetadataProviders, initialStatusMappings, initialSeriesStatuses, initialProviderStatuses }: SettingsPageProps) {
|
||||
const { t, locale, setLocale } = useTranslation();
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -521,28 +531,28 @@ export default function SettingsPage({ initialSettings, initialCacheStats, initi
|
||||
|
||||
{activeTab === "metadata" && (<>
|
||||
{/* Metadata Providers */}
|
||||
<MetadataProvidersCard handleUpdateSetting={handleUpdateSetting} />
|
||||
<MetadataProvidersCard handleUpdateSetting={handleUpdateSetting} initialData={initialMetadataProviders} />
|
||||
|
||||
{/* Status Mappings */}
|
||||
<StatusMappingsCard />
|
||||
<StatusMappingsCard initialStatusMappings={initialStatusMappings} initialSeriesStatuses={initialSeriesStatuses} initialProviderStatuses={initialProviderStatuses} />
|
||||
</>)}
|
||||
|
||||
{activeTab === "downloadTools" && (<>
|
||||
{/* Prowlarr */}
|
||||
<ProwlarrCard handleUpdateSetting={handleUpdateSetting} />
|
||||
<ProwlarrCard handleUpdateSetting={handleUpdateSetting} initialData={initialProwlarr} />
|
||||
|
||||
{/* qBittorrent */}
|
||||
<QBittorrentCard handleUpdateSetting={handleUpdateSetting} />
|
||||
<QBittorrentCard handleUpdateSetting={handleUpdateSetting} initialQbittorrent={initialQbittorrent} initialTorrentImport={initialTorrentImport} />
|
||||
</>)}
|
||||
|
||||
{activeTab === "notifications" && (<>
|
||||
{/* Telegram Notifications */}
|
||||
<TelegramCard handleUpdateSetting={handleUpdateSetting} />
|
||||
<TelegramCard handleUpdateSetting={handleUpdateSetting} initialData={initialTelegram} />
|
||||
</>)}
|
||||
|
||||
{activeTab === "readingStatus" && (<>
|
||||
<AnilistTab handleUpdateSetting={handleUpdateSetting} users={users} />
|
||||
<KomgaSyncCard users={users} />
|
||||
<AnilistTab handleUpdateSetting={handleUpdateSetting} users={users} initialData={initialAnilist} />
|
||||
<KomgaSyncCard users={users} initialData={initialKomga} />
|
||||
</>)}
|
||||
|
||||
<Toaster />
|
||||
|
||||
@@ -8,19 +8,21 @@ import { useTranslation } from "@/lib/i18n/context";
|
||||
export function AnilistTab({
|
||||
handleUpdateSetting,
|
||||
users,
|
||||
initialData,
|
||||
}: {
|
||||
handleUpdateSetting: (key: string, value: unknown) => Promise<void>;
|
||||
users: UserDto[];
|
||||
initialData: Record<string, unknown> | null;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [origin, setOrigin] = useState("");
|
||||
useEffect(() => { setOrigin(window.location.origin); }, []);
|
||||
|
||||
const [clientId, setClientId] = useState("");
|
||||
const [token, setToken] = useState("");
|
||||
const [userId, setUserId] = useState("");
|
||||
const [localUserId, setLocalUserId] = useState("");
|
||||
const [clientId, setClientId] = useState(initialData?.client_id ? String(initialData.client_id) : "");
|
||||
const [token, setToken] = useState(initialData?.access_token ? String(initialData.access_token) : "");
|
||||
const [userId, setUserId] = useState(initialData?.user_id ? String(initialData.user_id) : "");
|
||||
const [localUserId, setLocalUserId] = useState(initialData?.local_user_id ? String(initialData.local_user_id) : "");
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [viewer, setViewer] = useState<AnilistStatusDto | null>(null);
|
||||
const [testError, setTestError] = useState<string | null>(null);
|
||||
@@ -33,21 +35,6 @@ export function AnilistTab({
|
||||
const [isPreviewing, setIsPreviewing] = useState(false);
|
||||
const [previewItems, setPreviewItems] = useState<AnilistSyncPreviewItemDto[] | null>(null);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/settings/anilist")
|
||||
.then((r) => r.ok ? r.json() : null)
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
if (data.client_id) setClientId(String(data.client_id));
|
||||
if (data.access_token) setToken(data.access_token);
|
||||
if (data.user_id) setUserId(String(data.user_id));
|
||||
if (data.local_user_id) setLocalUserId(String(data.local_user_id));
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
function buildAnilistSettings() {
|
||||
return {
|
||||
client_id: clientId || undefined,
|
||||
|
||||
@@ -5,12 +5,12 @@ import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, Form
|
||||
import { KomgaSyncResponse, KomgaSyncReportSummary, UserDto } from "@/lib/api";
|
||||
import { useTranslation } from "@/lib/i18n/context";
|
||||
|
||||
export function KomgaSyncCard({ users }: { users: UserDto[] }) {
|
||||
export function KomgaSyncCard({ users, initialData }: { users: UserDto[]; initialData: Record<string, unknown> | null }) {
|
||||
const { t, locale } = useTranslation();
|
||||
const [komgaUrl, setKomgaUrl] = useState("");
|
||||
const [komgaUsername, setKomgaUsername] = useState("");
|
||||
const [komgaUrl, setKomgaUrl] = useState(initialData?.url ? String(initialData.url) : "");
|
||||
const [komgaUsername, setKomgaUsername] = useState(initialData?.username ? String(initialData.username) : "");
|
||||
const [komgaPassword, setKomgaPassword] = useState("");
|
||||
const [komgaUserId, setKomgaUserId] = useState(users[0]?.id ?? "");
|
||||
const [komgaUserId, setKomgaUserId] = useState(initialData?.user_id ? String(initialData.user_id) : (users[0]?.id ?? ""));
|
||||
const [isSyncing, setIsSyncing] = useState(false);
|
||||
const [syncResult, setSyncResult] = useState<KomgaSyncResponse | null>(null);
|
||||
const [syncError, setSyncError] = useState<string | null>(null);
|
||||
@@ -39,13 +39,6 @@ export function KomgaSyncCard({ users }: { users: UserDto[] }) {
|
||||
|
||||
useEffect(() => {
|
||||
fetchReports();
|
||||
fetch("/api/settings/komga").then(r => r.ok ? r.json() : null).then(data => {
|
||||
if (data) {
|
||||
if (data.url) setKomgaUrl(data.url);
|
||||
if (data.username) setKomgaUsername(data.username);
|
||||
if (data.user_id) setKomgaUserId(data.user_id);
|
||||
}
|
||||
}).catch(() => {});
|
||||
}, [fetchReports]);
|
||||
|
||||
async function handleViewReport(id: string) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, FormField, FormInput, FormSelect, Icon } from "@/app/components/ui";
|
||||
import { ProviderIcon } from "@/app/components/ProviderIcon";
|
||||
import { useTranslation } from "@/lib/i18n/context";
|
||||
@@ -11,25 +11,22 @@ export const METADATA_LANGUAGES = [
|
||||
{ value: "es", label: "Español" },
|
||||
] as const;
|
||||
|
||||
export function MetadataProvidersCard({ handleUpdateSetting }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void> }) {
|
||||
const { t } = useTranslation();
|
||||
const [defaultProvider, setDefaultProvider] = useState("google_books");
|
||||
const [metadataLanguage, setMetadataLanguage] = useState("en");
|
||||
const [apiKeys, setApiKeys] = useState<Record<string, string>>({});
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/settings/metadata_providers")
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((data) => {
|
||||
function extractInitialApiKeys(data: Record<string, unknown> | null): Record<string, string> {
|
||||
const keys: Record<string, string> = {};
|
||||
if (data) {
|
||||
if (data.default_provider) setDefaultProvider(data.default_provider);
|
||||
if (data.metadata_language) setMetadataLanguage(data.metadata_language);
|
||||
if (data.comicvine?.api_key) setApiKeys((prev) => ({ ...prev, comicvine: data.comicvine.api_key }));
|
||||
if (data.google_books?.api_key) setApiKeys((prev) => ({ ...prev, google_books: data.google_books.api_key }));
|
||||
const comicvine = data.comicvine as Record<string, unknown> | undefined;
|
||||
const googleBooks = data.google_books as Record<string, unknown> | undefined;
|
||||
if (comicvine?.api_key) keys.comicvine = String(comicvine.api_key);
|
||||
if (googleBooks?.api_key) keys.google_books = String(googleBooks.api_key);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
return keys;
|
||||
}
|
||||
|
||||
export function MetadataProvidersCard({ handleUpdateSetting, initialData }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void>; initialData: Record<string, unknown> | null }) {
|
||||
const { t } = useTranslation();
|
||||
const [defaultProvider, setDefaultProvider] = useState(initialData?.default_provider ? String(initialData.default_provider) : "google_books");
|
||||
const [metadataLanguage, setMetadataLanguage] = useState(initialData?.metadata_language ? String(initialData.metadata_language) : "en");
|
||||
const [apiKeys, setApiKeys] = useState<Record<string, string>>(extractInitialApiKeys(initialData));
|
||||
|
||||
function save(provider: string, lang: string, keys: Record<string, string>) {
|
||||
const value: Record<string, unknown> = {
|
||||
|
||||
@@ -1,30 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, FormField, FormInput, Icon } from "@/app/components/ui";
|
||||
import { useTranslation } from "@/lib/i18n/context";
|
||||
|
||||
export function ProwlarrCard({ handleUpdateSetting }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void> }) {
|
||||
export function ProwlarrCard({ handleUpdateSetting, initialData }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void>; initialData: Record<string, unknown> | null }) {
|
||||
const { t } = useTranslation();
|
||||
const [prowlarrUrl, setProwlarrUrl] = useState("");
|
||||
const [prowlarrApiKey, setProwlarrApiKey] = useState("");
|
||||
const [prowlarrCategories, setProwlarrCategories] = useState("7030, 7020");
|
||||
const [prowlarrUrl, setProwlarrUrl] = useState(initialData?.url ? String(initialData.url) : "");
|
||||
const [prowlarrApiKey, setProwlarrApiKey] = useState(initialData?.api_key ? String(initialData.api_key) : "");
|
||||
const [prowlarrCategories, setProwlarrCategories] = useState(
|
||||
Array.isArray(initialData?.categories) ? (initialData.categories as number[]).join(", ") : "7030, 7020"
|
||||
);
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/settings/prowlarr")
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
if (data.url) setProwlarrUrl(data.url);
|
||||
if (data.api_key) setProwlarrApiKey(data.api_key);
|
||||
if (data.categories) setProwlarrCategories(data.categories.join(", "));
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
function saveProwlarr(url?: string, apiKey?: string, cats?: string) {
|
||||
const categories = (cats ?? prowlarrCategories)
|
||||
.split(",")
|
||||
|
||||
@@ -1,34 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, FormField, FormInput, FormSelect, Icon } from "@/app/components/ui";
|
||||
import { useTranslation } from "@/lib/i18n/context";
|
||||
|
||||
export function QBittorrentCard({ handleUpdateSetting }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void> }) {
|
||||
export function QBittorrentCard({ handleUpdateSetting, initialQbittorrent, initialTorrentImport }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void>; initialQbittorrent: Record<string, unknown> | null; initialTorrentImport: Record<string, unknown> | null }) {
|
||||
const { t } = useTranslation();
|
||||
const [qbUrl, setQbUrl] = useState("");
|
||||
const [qbUsername, setQbUsername] = useState("");
|
||||
const [qbPassword, setQbPassword] = useState("");
|
||||
const [qbUrl, setQbUrl] = useState(initialQbittorrent?.url ? String(initialQbittorrent.url) : "");
|
||||
const [qbUsername, setQbUsername] = useState(initialQbittorrent?.username ? String(initialQbittorrent.username) : "");
|
||||
const [qbPassword, setQbPassword] = useState(initialQbittorrent?.password ? String(initialQbittorrent.password) : "");
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null);
|
||||
const [importEnabled, setImportEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/settings/qbittorrent")
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
if (data.url) setQbUrl(data.url);
|
||||
if (data.username) setQbUsername(data.username);
|
||||
if (data.password) setQbPassword(data.password);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
fetch("/api/settings/torrent_import")
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((data) => { if (data?.enabled !== undefined) setImportEnabled(data.enabled); })
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
const [importEnabled, setImportEnabled] = useState(initialTorrentImport?.enabled === true);
|
||||
|
||||
function saveQbittorrent() {
|
||||
handleUpdateSetting("qbittorrent", {
|
||||
|
||||
@@ -1,36 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback, useMemo } from "react";
|
||||
import { useState, useMemo } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, FormField, FormInput, FormSelect, Icon } from "@/app/components/ui";
|
||||
import { StatusMappingDto } from "@/lib/api";
|
||||
import { useTranslation } from "@/lib/i18n/context";
|
||||
|
||||
export function StatusMappingsCard() {
|
||||
export function StatusMappingsCard({ initialStatusMappings, initialSeriesStatuses, initialProviderStatuses }: { initialStatusMappings: Record<string, unknown>[]; initialSeriesStatuses: string[]; initialProviderStatuses: string[] }) {
|
||||
const { t } = useTranslation();
|
||||
const [mappings, setMappings] = useState<StatusMappingDto[]>([]);
|
||||
const [targetStatuses, setTargetStatuses] = useState<string[]>([]);
|
||||
const [providerStatuses, setProviderStatuses] = useState<string[]>([]);
|
||||
const [mappings, setMappings] = useState<StatusMappingDto[]>(initialStatusMappings as unknown as StatusMappingDto[]);
|
||||
const [targetStatuses, setTargetStatuses] = useState<string[]>(initialSeriesStatuses);
|
||||
const [providerStatuses] = useState<string[]>(initialProviderStatuses);
|
||||
const [newTargetName, setNewTargetName] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
try {
|
||||
const [mRes, sRes, pRes] = await Promise.all([
|
||||
fetch("/api/settings/status-mappings").then((r) => r.ok ? r.json() : []),
|
||||
fetch("/api/series/statuses").then((r) => r.ok ? r.json() : []),
|
||||
fetch("/api/series/provider-statuses").then((r) => r.ok ? r.json() : []),
|
||||
]);
|
||||
setMappings(mRes);
|
||||
setTargetStatuses(sRes);
|
||||
setProviderStatuses(pRes);
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => { loadData(); }, [loadData]);
|
||||
|
||||
// Group mappings by target status (only those with a non-null mapped_status)
|
||||
const grouped = useMemo(() => {
|
||||
@@ -108,14 +88,6 @@ export function StatusMappingsCard() {
|
||||
return translated !== key ? translated : status;
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Card className="mb-6">
|
||||
<CardContent><p className="text-muted-foreground py-4">{t("common.loading")}</p></CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="mb-6">
|
||||
<CardHeader>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, FormField, FormInput, Icon } from "@/app/components/ui";
|
||||
import { useTranslation } from "@/lib/i18n/context";
|
||||
|
||||
@@ -25,30 +25,18 @@ export const DEFAULT_EVENTS = {
|
||||
download_detection_failed: true,
|
||||
};
|
||||
|
||||
export function TelegramCard({ handleUpdateSetting }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void> }) {
|
||||
export function TelegramCard({ handleUpdateSetting, initialData }: { handleUpdateSetting: (key: string, value: unknown) => Promise<void>; initialData: Record<string, unknown> | null }) {
|
||||
const { t } = useTranslation();
|
||||
const [botToken, setBotToken] = useState("");
|
||||
const [chatId, setChatId] = useState("");
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const [events, setEvents] = useState(DEFAULT_EVENTS);
|
||||
const [botToken, setBotToken] = useState(initialData?.bot_token ? String(initialData.bot_token) : "");
|
||||
const [chatId, setChatId] = useState(initialData?.chat_id ? String(initialData.chat_id) : "");
|
||||
const [enabled, setEnabled] = useState(initialData?.enabled === true);
|
||||
const [events, setEvents] = useState(
|
||||
initialData?.events ? { ...DEFAULT_EVENTS, ...(initialData.events as Record<string, boolean>) } : DEFAULT_EVENTS
|
||||
);
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null);
|
||||
const [showHelp, setShowHelp] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/settings/telegram")
|
||||
.then((r) => (r.ok ? r.json() : null))
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
if (data.bot_token) setBotToken(data.bot_token);
|
||||
if (data.chat_id) setChatId(data.chat_id);
|
||||
if (data.enabled !== undefined) setEnabled(data.enabled);
|
||||
if (data.events) setEvents({ ...DEFAULT_EVENTS, ...data.events });
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
function saveTelegram(token?: string, chat?: string, en?: boolean, ev?: typeof events) {
|
||||
handleUpdateSetting("telegram", {
|
||||
bot_token: token ?? botToken,
|
||||
|
||||
@@ -1,30 +1,49 @@
|
||||
import { getSettings, getCacheStats, getThumbnailStats, fetchUsers } from "@/lib/api";
|
||||
import { getSettings, getCacheStats, getThumbnailStats, fetchUsers, apiFetch } from "@/lib/api";
|
||||
import SettingsPage from "./SettingsPage";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function SettingsPageWrapper({ searchParams }: { searchParams: Promise<{ tab?: string }> }) {
|
||||
const { tab } = await searchParams;
|
||||
const settings = await getSettings().catch(() => ({
|
||||
const [settings, cacheStats, thumbnailStats, users, prowlarr, qbittorrent, torrentImport, telegram, anilist, komga, metadataProviders, statusMappings, seriesStatuses, providerStatuses] = 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 },
|
||||
limits: { concurrent_renders: 4, timeout_seconds: 12, rate_limit_per_second: 120 },
|
||||
thumbnail: { enabled: true, width: 300, height: 400, quality: 80, format: "webp", directory: "/data/thumbnails" }
|
||||
}));
|
||||
})),
|
||||
getCacheStats().catch(() => ({ total_size_mb: 0, file_count: 0, directory: "/tmp/stripstream-image-cache" })),
|
||||
getThumbnailStats().catch(() => ({ total_size_mb: 0, file_count: 0, directory: "/data/thumbnails" })),
|
||||
fetchUsers().catch(() => []),
|
||||
apiFetch<Record<string, unknown>>("/settings/prowlarr").catch(() => null),
|
||||
apiFetch<Record<string, unknown>>("/settings/qbittorrent").catch(() => null),
|
||||
apiFetch<Record<string, unknown>>("/settings/torrent_import").catch(() => null),
|
||||
apiFetch<Record<string, unknown>>("/settings/telegram").catch(() => null),
|
||||
apiFetch<Record<string, unknown>>("/settings/anilist").catch(() => null),
|
||||
apiFetch<Record<string, unknown>>("/settings/komga").catch(() => null),
|
||||
apiFetch<Record<string, unknown>>("/settings/metadata_providers").catch(() => null),
|
||||
apiFetch<unknown[]>("/settings/status-mappings").catch(() => []),
|
||||
apiFetch<unknown[]>("/series/statuses").catch(() => []),
|
||||
apiFetch<unknown[]>("/series/provider-statuses").catch(() => []),
|
||||
]);
|
||||
|
||||
const cacheStats = await getCacheStats().catch(() => ({
|
||||
total_size_mb: 0,
|
||||
file_count: 0,
|
||||
directory: "/tmp/stripstream-image-cache"
|
||||
}));
|
||||
|
||||
const thumbnailStats = await getThumbnailStats().catch(() => ({
|
||||
total_size_mb: 0,
|
||||
file_count: 0,
|
||||
directory: "/data/thumbnails"
|
||||
}));
|
||||
|
||||
const users = await fetchUsers().catch(() => []);
|
||||
|
||||
return <SettingsPage initialSettings={settings} initialCacheStats={cacheStats} initialThumbnailStats={thumbnailStats} users={users} initialTab={tab} />;
|
||||
return (
|
||||
<SettingsPage
|
||||
initialSettings={settings}
|
||||
initialCacheStats={cacheStats}
|
||||
initialThumbnailStats={thumbnailStats}
|
||||
users={users}
|
||||
initialTab={tab}
|
||||
initialProwlarr={prowlarr}
|
||||
initialQbittorrent={qbittorrent}
|
||||
initialTorrentImport={torrentImport}
|
||||
initialTelegram={telegram}
|
||||
initialAnilist={anilist}
|
||||
initialKomga={komga}
|
||||
initialMetadataProviders={metadataProviders}
|
||||
initialStatusMappings={statusMappings as Record<string, unknown>[]}
|
||||
initialSeriesStatuses={seriesStatuses as string[]}
|
||||
initialProviderStatuses={providerStatuses as string[]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user