Initial release v1.0.0
This commit is contained in:
210
frontend/features/settings/hooks/useSystemSettings.ts
Normal file
210
frontend/features/settings/hooks/useSystemSettings.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { api } from "@/lib/api";
|
||||
import { useAuth } from "@/lib/auth-context";
|
||||
import { SystemSettings } from "../types";
|
||||
|
||||
const defaultSystemSettings: SystemSettings = {
|
||||
lidarrEnabled: true,
|
||||
lidarrUrl: "http://localhost:8686",
|
||||
lidarrApiKey: "",
|
||||
openaiEnabled: false,
|
||||
openaiApiKey: "",
|
||||
openaiModel: "gpt-4",
|
||||
fanartEnabled: false,
|
||||
fanartApiKey: "",
|
||||
audiobookshelfEnabled: false,
|
||||
audiobookshelfUrl: "http://localhost:13378",
|
||||
audiobookshelfApiKey: "",
|
||||
soulseekUsername: "",
|
||||
soulseekPassword: "",
|
||||
spotifyClientId: "",
|
||||
spotifyClientSecret: "",
|
||||
musicPath: "/music",
|
||||
downloadPath: "/downloads",
|
||||
transcodeCacheMaxGb: 10,
|
||||
maxCacheSizeMb: 10240,
|
||||
autoSync: true,
|
||||
autoEnrichMetadata: true,
|
||||
// Download preferences
|
||||
downloadSource: "soulseek",
|
||||
soulseekFallback: "none",
|
||||
};
|
||||
|
||||
export function useSystemSettings() {
|
||||
const { isAuthenticated, user } = useAuth();
|
||||
const [systemSettings, setSystemSettings] = useState<SystemSettings>(
|
||||
defaultSystemSettings
|
||||
);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [changedServices, setChangedServices] = useState<string[]>([]);
|
||||
const [originalSettings, setOriginalSettings] = useState<SystemSettings>(
|
||||
defaultSystemSettings
|
||||
);
|
||||
|
||||
const isAdmin = user?.role === "admin";
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated && isAdmin) {
|
||||
loadSystemSettings();
|
||||
}
|
||||
}, [isAuthenticated, isAdmin]);
|
||||
|
||||
const loadSystemSettings = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const [sysData, userData] = await Promise.all([
|
||||
api.getSystemSettings(),
|
||||
api.getSettings(),
|
||||
]);
|
||||
|
||||
// Sanitize null values to empty strings for controlled inputs
|
||||
const sanitizeSettings = (settings: any): SystemSettings => {
|
||||
const sanitized: any = {};
|
||||
for (const key in settings) {
|
||||
const value = settings[key];
|
||||
// Convert null to empty string for string fields
|
||||
if (value === null && typeof defaultSystemSettings[key as keyof SystemSettings] === 'string') {
|
||||
sanitized[key] = '';
|
||||
} else {
|
||||
sanitized[key] = value;
|
||||
}
|
||||
}
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
const combinedSettings = {
|
||||
...sanitizeSettings(sysData),
|
||||
maxCacheSizeMb: userData.maxCacheSizeMb,
|
||||
};
|
||||
|
||||
setSystemSettings(combinedSettings);
|
||||
setOriginalSettings(combinedSettings);
|
||||
} catch (error) {
|
||||
console.error("Failed to load system settings:", error);
|
||||
// No toast - error will be visible in the UI if settings fail to load
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const saveSystemSettings = async (settingsToSave: SystemSettings, showToast = false) => {
|
||||
try {
|
||||
setIsSaving(true);
|
||||
|
||||
// Save system settings
|
||||
await api.updateSystemSettings(settingsToSave);
|
||||
|
||||
// Also save user cache setting
|
||||
await api.updateSettings({
|
||||
maxCacheSizeMb: settingsToSave.maxCacheSizeMb,
|
||||
});
|
||||
|
||||
// Determine which services changed
|
||||
const changed: string[] = [];
|
||||
if (
|
||||
originalSettings.lidarrEnabled !==
|
||||
settingsToSave.lidarrEnabled ||
|
||||
originalSettings.lidarrUrl !== settingsToSave.lidarrUrl ||
|
||||
originalSettings.lidarrApiKey !== settingsToSave.lidarrApiKey
|
||||
) {
|
||||
changed.push("Lidarr");
|
||||
}
|
||||
if (
|
||||
originalSettings.soulseekUsername !== settingsToSave.soulseekUsername ||
|
||||
originalSettings.soulseekPassword !== settingsToSave.soulseekPassword
|
||||
) {
|
||||
changed.push("Soulseek");
|
||||
}
|
||||
if (
|
||||
originalSettings.audiobookshelfEnabled !==
|
||||
settingsToSave.audiobookshelfEnabled ||
|
||||
originalSettings.audiobookshelfUrl !==
|
||||
settingsToSave.audiobookshelfUrl ||
|
||||
originalSettings.audiobookshelfApiKey !==
|
||||
settingsToSave.audiobookshelfApiKey
|
||||
) {
|
||||
changed.push("Audiobookshelf");
|
||||
}
|
||||
|
||||
setChangedServices(changed);
|
||||
setOriginalSettings(settingsToSave);
|
||||
|
||||
return changed; // Return changed services
|
||||
} catch (error) {
|
||||
console.error("Failed to save system settings:", error);
|
||||
throw error; // Caller handles the error display
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const updateSystemSettings = (updates: Partial<SystemSettings>) => {
|
||||
setSystemSettings((prev) => ({ ...prev, ...updates }));
|
||||
};
|
||||
|
||||
/**
|
||||
* Test a service connection
|
||||
* Returns { success: true, version?: string } or { success: false, error: string }
|
||||
* Caller handles displaying the result inline
|
||||
*/
|
||||
const testService = async (service: string): Promise<{ success: boolean; version?: string; error?: string }> => {
|
||||
try {
|
||||
let result;
|
||||
switch (service) {
|
||||
case "lidarr":
|
||||
result = await api.testLidarr(
|
||||
systemSettings.lidarrUrl,
|
||||
systemSettings.lidarrApiKey
|
||||
);
|
||||
break;
|
||||
case "openai":
|
||||
result = await api.testOpenai(
|
||||
systemSettings.openaiApiKey,
|
||||
systemSettings.openaiModel
|
||||
);
|
||||
break;
|
||||
case "fanart":
|
||||
result = await api.testFanart(systemSettings.fanartApiKey);
|
||||
break;
|
||||
case "audiobookshelf":
|
||||
result = await api.testAudiobookshelf(
|
||||
systemSettings.audiobookshelfUrl,
|
||||
systemSettings.audiobookshelfApiKey
|
||||
);
|
||||
break;
|
||||
case "soulseek":
|
||||
result = await api.testSoulseek(
|
||||
systemSettings.soulseekUsername,
|
||||
systemSettings.soulseekPassword
|
||||
);
|
||||
break;
|
||||
case "spotify":
|
||||
result = await api.testSpotify(
|
||||
systemSettings.spotifyClientId,
|
||||
systemSettings.spotifyClientSecret
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown service: ${service}`);
|
||||
}
|
||||
|
||||
return { success: true, version: result?.version };
|
||||
} catch (error: any) {
|
||||
console.error(`Failed to test ${service}:`, error);
|
||||
return { success: false, error: error.message || `Failed to connect` };
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
systemSettings,
|
||||
isLoading,
|
||||
isSaving,
|
||||
changedServices,
|
||||
setSystemSettings,
|
||||
updateSystemSettings,
|
||||
saveSystemSettings,
|
||||
testService,
|
||||
loadSystemSettings,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user