mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
Add BookDate card stack animations and thumbnail caching
Implements pure CSS card stack animations for BookDate recommendations, including smooth exit and advance transitions. Adds local caching of library cover thumbnails during scans, updates database schema and API to serve cached covers, and enhances BookDate to support 'favorites' scope with a book picker modal. Updates admin settings validation logic for Prowlarr, improves indexer state management, and documents new features and backend changes.
This commit is contained in:
@@ -163,6 +163,7 @@ export const validateAuthSettings = (settings: Settings): { valid: boolean; mess
|
||||
export const getTabValidation = (
|
||||
activeTab: SettingsTab,
|
||||
settings: Settings,
|
||||
originalSettings: Settings | null,
|
||||
validated: {
|
||||
plex: boolean;
|
||||
audiobookshelf: boolean;
|
||||
@@ -179,7 +180,15 @@ export const getTabValidation = (
|
||||
case 'auth':
|
||||
return validated.oidc || validated.registration;
|
||||
case 'prowlarr':
|
||||
return validated.prowlarr;
|
||||
// Only require validation if URL or API key changed
|
||||
// If only indexers/flags changed, allow saving without test
|
||||
if (!originalSettings) return validated.prowlarr;
|
||||
|
||||
const prowlarrConnectionChanged =
|
||||
settings.prowlarr.url !== originalSettings.prowlarr.url ||
|
||||
settings.prowlarr.apiKey !== originalSettings.prowlarr.apiKey;
|
||||
|
||||
return prowlarrConnectionChanged ? validated.prowlarr : true;
|
||||
case 'download':
|
||||
return validated.download;
|
||||
case 'paths':
|
||||
|
||||
@@ -49,7 +49,9 @@ export default function AdminSettings() {
|
||||
|
||||
// Indexer-specific state (used by IndexersTab)
|
||||
const [configuredIndexers, setConfiguredIndexers] = useState<SavedIndexerConfig[]>([]);
|
||||
const [originalConfiguredIndexers, setOriginalConfiguredIndexers] = useState<SavedIndexerConfig[]>([]);
|
||||
const [flagConfigs, setFlagConfigs] = useState<IndexerFlagConfig[]>([]);
|
||||
const [originalFlagConfigs, setOriginalFlagConfigs] = useState<IndexerFlagConfig[]>([]);
|
||||
|
||||
// Initial data fetch
|
||||
useEffect(() => {
|
||||
@@ -89,7 +91,9 @@ export default function AdminSettings() {
|
||||
const response = await fetchWithAuth('/api/admin/settings/prowlarr/indexers');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setFlagConfigs(data.flagConfigs || []);
|
||||
const flags = data.flagConfigs || [];
|
||||
setFlagConfigs(flags);
|
||||
setOriginalFlagConfigs(JSON.parse(JSON.stringify(flags)));
|
||||
|
||||
// Extract configured indexers (enabled ones)
|
||||
const configured = (data.indexers || [])
|
||||
@@ -103,6 +107,7 @@ export default function AdminSettings() {
|
||||
categories: idx.categories || [3030],
|
||||
}));
|
||||
setConfiguredIndexers(configured);
|
||||
setOriginalConfiguredIndexers(JSON.parse(JSON.stringify(configured)));
|
||||
} else {
|
||||
console.error('Failed to fetch indexers:', response.status);
|
||||
if (force) {
|
||||
@@ -139,6 +144,13 @@ export default function AdminSettings() {
|
||||
await saveTabSettings(activeTab, settings, configuredIndexers, flagConfigs);
|
||||
setMessage({ type: 'success', text: 'Settings saved successfully!' });
|
||||
setOriginalSettings(JSON.parse(JSON.stringify(settings)));
|
||||
|
||||
// Also update original indexers and flag configs when saving prowlarr tab
|
||||
if (activeTab === 'prowlarr') {
|
||||
setOriginalConfiguredIndexers(JSON.parse(JSON.stringify(configuredIndexers)));
|
||||
setOriginalFlagConfigs(JSON.parse(JSON.stringify(flagConfigs)));
|
||||
}
|
||||
|
||||
setTimeout(() => setMessage(null), 3000);
|
||||
} catch (error) {
|
||||
setMessage({
|
||||
@@ -161,8 +173,21 @@ export default function AdminSettings() {
|
||||
|
||||
// Dynamic tabs, validation, and change detection
|
||||
const tabs = getTabs(settings.backendMode);
|
||||
const currentTabValidation = getTabValidation(activeTab, settings, validated);
|
||||
const hasUnsavedChanges = JSON.stringify(settings) !== JSON.stringify(originalSettings);
|
||||
const currentTabValidation = getTabValidation(activeTab, settings, originalSettings, validated);
|
||||
|
||||
// Check for unsaved changes in settings and indexer-specific state
|
||||
const hasUnsavedChanges = (() => {
|
||||
const settingsChanged = JSON.stringify(settings) !== JSON.stringify(originalSettings);
|
||||
|
||||
// For prowlarr tab, also check indexers and flag configs
|
||||
if (activeTab === 'prowlarr') {
|
||||
const indexersChanged = JSON.stringify(configuredIndexers) !== JSON.stringify(originalConfiguredIndexers);
|
||||
const flagConfigsChanged = JSON.stringify(flagConfigs) !== JSON.stringify(originalFlagConfigs);
|
||||
return settingsChanged || indexersChanged || flagConfigsChanged;
|
||||
}
|
||||
|
||||
return settingsChanged;
|
||||
})();
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
||||
@@ -315,7 +340,9 @@ export default function AdminSettings() {
|
||||
</Button>
|
||||
{!currentTabValidation && hasUnsavedChanges && (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 self-center">
|
||||
Please test the connection before saving
|
||||
{activeTab === 'prowlarr'
|
||||
? 'Please test the Prowlarr connection before saving'
|
||||
: 'Please test the connection before saving'}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user