mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat: add API endpoint for fetching application settings and update frontend settings management
This commit is contained in:
@@ -88,6 +88,7 @@ class MiscRoutes:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def setup_routes(app):
|
def setup_routes(app):
|
||||||
"""Register miscellaneous routes"""
|
"""Register miscellaneous routes"""
|
||||||
|
app.router.add_get('/api/settings', MiscRoutes.get_settings)
|
||||||
app.router.add_post('/api/settings', MiscRoutes.update_settings)
|
app.router.add_post('/api/settings', MiscRoutes.update_settings)
|
||||||
|
|
||||||
app.router.add_get('/api/health-check', lambda request: web.json_response({'status': 'ok'}))
|
app.router.add_get('/api/health-check', lambda request: web.json_response({'status': 'ok'}))
|
||||||
@@ -119,6 +120,47 @@ class MiscRoutes:
|
|||||||
app.router.add_post('/api/remove-metadata-archive', MiscRoutes.remove_metadata_archive)
|
app.router.add_post('/api/remove-metadata-archive', MiscRoutes.remove_metadata_archive)
|
||||||
app.router.add_get('/api/metadata-archive-status', MiscRoutes.get_metadata_archive_status)
|
app.router.add_get('/api/metadata-archive-status', MiscRoutes.get_metadata_archive_status)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def get_settings(request):
|
||||||
|
"""Get application settings that should be synced to frontend"""
|
||||||
|
try:
|
||||||
|
# Define keys that should be synced from backend to frontend
|
||||||
|
sync_keys = [
|
||||||
|
'civitai_api_key',
|
||||||
|
'default_lora_root',
|
||||||
|
'default_checkpoint_root',
|
||||||
|
'default_embedding_root',
|
||||||
|
'base_model_path_mappings',
|
||||||
|
'download_path_templates',
|
||||||
|
'enable_metadata_archive_db',
|
||||||
|
'language',
|
||||||
|
'proxy_enabled',
|
||||||
|
'proxy_type',
|
||||||
|
'proxy_host',
|
||||||
|
'proxy_port',
|
||||||
|
'proxy_username',
|
||||||
|
'proxy_password'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Build response with only the keys that should be synced
|
||||||
|
response_data = {}
|
||||||
|
for key in sync_keys:
|
||||||
|
value = settings.get(key)
|
||||||
|
if value is not None:
|
||||||
|
response_data[key] = value
|
||||||
|
|
||||||
|
return web.json_response({
|
||||||
|
'success': True,
|
||||||
|
'settings': response_data
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error getting settings: {e}", exc_info=True)
|
||||||
|
return web.json_response({
|
||||||
|
'success': False,
|
||||||
|
'error': str(e)
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def update_settings(request):
|
async def update_settings(request):
|
||||||
"""Update application settings"""
|
"""Update application settings"""
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ class SettingsManager:
|
|||||||
"""Return default settings"""
|
"""Return default settings"""
|
||||||
return {
|
return {
|
||||||
"civitai_api_key": "",
|
"civitai_api_key": "",
|
||||||
"show_only_sfw": False,
|
|
||||||
"language": "en",
|
"language": "en",
|
||||||
"enable_metadata_archive_db": False, # Enable metadata archive database
|
"enable_metadata_archive_db": False, # Enable metadata archive database
|
||||||
"proxy_enabled": False, # Enable app-level proxy
|
"proxy_enabled": False, # Enable app-level proxy
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"civitai_api_key": "your_civitai_api_key_here",
|
"civitai_api_key": "your_civitai_api_key_here",
|
||||||
"show_only_sfw": false,
|
|
||||||
"folder_paths": {
|
"folder_paths": {
|
||||||
"loras": [
|
"loras": [
|
||||||
"C:/path/to/your/loras_folder",
|
"C:/path/to/your/loras_folder",
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ export class AppCore {
|
|||||||
|
|
||||||
console.log(`AppCore: Language set: ${i18n.getCurrentLocale()}`);
|
console.log(`AppCore: Language set: ${i18n.getCurrentLocale()}`);
|
||||||
|
|
||||||
|
// Initialize settings manager and wait for it to sync from backend
|
||||||
|
console.log('AppCore: Initializing settings...');
|
||||||
|
await settingsManager.waitForInitialization();
|
||||||
|
console.log('AppCore: Settings initialized');
|
||||||
|
|
||||||
// Initialize managers
|
// Initialize managers
|
||||||
state.loadingManager = new LoadingManager();
|
state.loadingManager = new LoadingManager();
|
||||||
modalManager.initialize();
|
modalManager.initialize();
|
||||||
|
|||||||
@@ -10,122 +10,194 @@ export class SettingsManager {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.initialized = false;
|
this.initialized = false;
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
|
this.initializationPromise = null;
|
||||||
|
|
||||||
// Add initialization to sync with modal state
|
// Add initialization to sync with modal state
|
||||||
this.currentPage = document.body.dataset.page || 'loras';
|
this.currentPage = document.body.dataset.page || 'loras';
|
||||||
|
|
||||||
// Ensure settings are loaded from localStorage
|
// Start initialization but don't await here to avoid blocking constructor
|
||||||
this.loadSettingsFromStorage();
|
this.initializationPromise = this.initializeSettings();
|
||||||
|
|
||||||
// Sync settings to backend if needed
|
|
||||||
this.syncSettingsToBackendIfNeeded();
|
|
||||||
|
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSettingsFromStorage() {
|
// Add method to wait for initialization to complete
|
||||||
|
async waitForInitialization() {
|
||||||
|
if (this.initializationPromise) {
|
||||||
|
await this.initializationPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async initializeSettings() {
|
||||||
|
// Load frontend-only settings from localStorage
|
||||||
|
this.loadFrontendSettingsFromStorage();
|
||||||
|
|
||||||
|
// Sync settings from backend to frontend
|
||||||
|
await this.syncSettingsFromBackend();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadFrontendSettingsFromStorage() {
|
||||||
// Get saved settings from localStorage
|
// Get saved settings from localStorage
|
||||||
const savedSettings = getStorageItem('settings');
|
const savedSettings = getStorageItem('settings');
|
||||||
|
|
||||||
// Migrate legacy default_loras_root to default_lora_root if present
|
// Frontend-only settings that should be stored in localStorage
|
||||||
if (savedSettings && savedSettings.default_loras_root && !savedSettings.default_lora_root) {
|
const frontendOnlyKeys = [
|
||||||
savedSettings.default_lora_root = savedSettings.default_loras_root;
|
'blurMatureContent',
|
||||||
delete savedSettings.default_loras_root;
|
'show_only_sfw',
|
||||||
setStorageItem('settings', savedSettings);
|
'autoplayOnHover',
|
||||||
}
|
'displayDensity',
|
||||||
|
'cardInfoDisplay',
|
||||||
|
'optimizeExampleImages',
|
||||||
|
'autoDownloadExampleImages',
|
||||||
|
'includeTriggerWords'
|
||||||
|
];
|
||||||
|
|
||||||
// Apply saved settings to state if available
|
// Apply saved frontend settings to state if available
|
||||||
if (savedSettings) {
|
if (savedSettings) {
|
||||||
state.global.settings = { ...state.global.settings, ...savedSettings };
|
const frontendSettings = {};
|
||||||
|
frontendOnlyKeys.forEach(key => {
|
||||||
|
if (savedSettings[key] !== undefined) {
|
||||||
|
frontendSettings[key] = savedSettings[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state.global.settings = { ...state.global.settings, ...frontendSettings };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize default values for new settings if they don't exist
|
// Initialize default values for frontend settings if they don't exist
|
||||||
if (state.global.settings.compactMode === undefined) {
|
if (state.global.settings.blurMatureContent === undefined) {
|
||||||
state.global.settings.compactMode = false;
|
state.global.settings.blurMatureContent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.global.settings.show_only_sfw === undefined) {
|
||||||
|
state.global.settings.show_only_sfw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.global.settings.autoplayOnHover === undefined) {
|
||||||
|
state.global.settings.autoplayOnHover = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default for optimizeExampleImages if undefined
|
|
||||||
if (state.global.settings.optimizeExampleImages === undefined) {
|
if (state.global.settings.optimizeExampleImages === undefined) {
|
||||||
state.global.settings.optimizeExampleImages = true;
|
state.global.settings.optimizeExampleImages = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default for autoDownloadExampleImages if undefined
|
|
||||||
if (state.global.settings.autoDownloadExampleImages === undefined) {
|
if (state.global.settings.autoDownloadExampleImages === undefined) {
|
||||||
state.global.settings.autoDownloadExampleImages = true;
|
state.global.settings.autoDownloadExampleImages = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default for cardInfoDisplay if undefined
|
|
||||||
if (state.global.settings.cardInfoDisplay === undefined) {
|
if (state.global.settings.cardInfoDisplay === undefined) {
|
||||||
state.global.settings.cardInfoDisplay = 'always';
|
state.global.settings.cardInfoDisplay = 'always';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default for defaultCheckpointRoot if undefined
|
if (state.global.settings.displayDensity === undefined) {
|
||||||
if (state.global.settings.default_checkpoint_root === undefined) {
|
// Migrate legacy compactMode if it exists
|
||||||
state.global.settings.default_checkpoint_root = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert old boolean compactMode to new displayDensity string
|
|
||||||
if (typeof state.global.settings.displayDensity === 'undefined') {
|
|
||||||
if (state.global.settings.compactMode === true) {
|
if (state.global.settings.compactMode === true) {
|
||||||
state.global.settings.displayDensity = 'compact';
|
state.global.settings.displayDensity = 'compact';
|
||||||
} else {
|
} else {
|
||||||
state.global.settings.displayDensity = 'default';
|
state.global.settings.displayDensity = 'default';
|
||||||
}
|
}
|
||||||
// We can delete the old setting, but keeping it for backwards compatibility
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate legacy download_path_template to new structure
|
|
||||||
if (state.global.settings.download_path_template && !state.global.settings.download_path_templates) {
|
|
||||||
const legacyTemplate = state.global.settings.download_path_template;
|
|
||||||
state.global.settings.download_path_templates = {
|
|
||||||
lora: legacyTemplate,
|
|
||||||
checkpoint: legacyTemplate,
|
|
||||||
embedding: legacyTemplate
|
|
||||||
};
|
|
||||||
delete state.global.settings.download_path_template;
|
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default for download path templates if undefined
|
|
||||||
if (state.global.settings.download_path_templates === undefined) {
|
|
||||||
state.global.settings.download_path_templates = { ...DEFAULT_PATH_TEMPLATES };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure all model types have templates
|
|
||||||
Object.keys(DEFAULT_PATH_TEMPLATES).forEach(modelType => {
|
|
||||||
if (typeof state.global.settings.download_path_templates[modelType] === 'undefined') {
|
|
||||||
state.global.settings.download_path_templates[modelType] = DEFAULT_PATH_TEMPLATES[modelType];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set default for base model path mappings if undefined
|
|
||||||
if (state.global.settings.base_model_path_mappings === undefined) {
|
|
||||||
state.global.settings.base_model_path_mappings = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default for defaultEmbeddingRoot if undefined
|
|
||||||
if (state.global.settings.default_embedding_root === undefined) {
|
|
||||||
state.global.settings.default_embedding_root = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default for includeTriggerWords if undefined
|
|
||||||
if (state.global.settings.includeTriggerWords === undefined) {
|
if (state.global.settings.includeTriggerWords === undefined) {
|
||||||
state.global.settings.includeTriggerWords = false;
|
state.global.settings.includeTriggerWords = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save updated frontend settings to localStorage
|
||||||
|
this.saveFrontendSettingsToStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
async syncSettingsToBackendIfNeeded() {
|
async syncSettingsFromBackend() {
|
||||||
// Get local settings from storage
|
try {
|
||||||
const localSettings = getStorageItem('settings') || {};
|
const response = await fetch('/api/settings');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.success && data.settings) {
|
||||||
|
// Merge backend settings with current state
|
||||||
|
state.global.settings = { ...state.global.settings, ...data.settings };
|
||||||
|
|
||||||
|
// Set defaults for backend settings if they're null/undefined
|
||||||
|
this.setBackendSettingDefaults();
|
||||||
|
|
||||||
|
console.log('Settings synced from backend');
|
||||||
|
} else {
|
||||||
|
console.error('Failed to sync settings from backend:', data.error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to sync settings from backend:', error);
|
||||||
|
// Set defaults if backend sync fails
|
||||||
|
this.setBackendSettingDefaults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fields that need to be synced to backend
|
setBackendSettingDefaults() {
|
||||||
const fieldsToSync = [
|
// Set defaults for backend settings
|
||||||
|
const backendDefaults = {
|
||||||
|
civitai_api_key: '',
|
||||||
|
default_lora_root: '',
|
||||||
|
default_checkpoint_root: '',
|
||||||
|
default_embedding_root: '',
|
||||||
|
base_model_path_mappings: {},
|
||||||
|
download_path_templates: { ...DEFAULT_PATH_TEMPLATES },
|
||||||
|
enable_metadata_archive_db: false,
|
||||||
|
language: 'en',
|
||||||
|
proxy_enabled: false,
|
||||||
|
proxy_type: 'http',
|
||||||
|
proxy_host: '',
|
||||||
|
proxy_port: '',
|
||||||
|
proxy_username: '',
|
||||||
|
proxy_password: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(backendDefaults).forEach(key => {
|
||||||
|
if (state.global.settings[key] === undefined || state.global.settings[key] === null) {
|
||||||
|
state.global.settings[key] = backendDefaults[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure all model types have templates
|
||||||
|
Object.keys(DEFAULT_PATH_TEMPLATES).forEach(modelType => {
|
||||||
|
if (!state.global.settings.download_path_templates[modelType]) {
|
||||||
|
state.global.settings.download_path_templates[modelType] = DEFAULT_PATH_TEMPLATES[modelType];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveFrontendSettingsToStorage() {
|
||||||
|
// Save only frontend-specific settings to localStorage
|
||||||
|
const frontendOnlyKeys = [
|
||||||
|
'blurMatureContent',
|
||||||
|
'show_only_sfw',
|
||||||
|
'autoplayOnHover',
|
||||||
|
'displayDensity',
|
||||||
|
'cardInfoDisplay',
|
||||||
|
'optimizeExampleImages',
|
||||||
|
'autoDownloadExampleImages',
|
||||||
|
'includeTriggerWords'
|
||||||
|
];
|
||||||
|
|
||||||
|
const frontendSettings = {};
|
||||||
|
frontendOnlyKeys.forEach(key => {
|
||||||
|
if (state.global.settings[key] !== undefined) {
|
||||||
|
frontendSettings[key] = state.global.settings[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setStorageItem('settings', frontendSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to determine if a setting should be saved to backend
|
||||||
|
isBackendSetting(settingKey) {
|
||||||
|
const backendKeys = [
|
||||||
'civitai_api_key',
|
'civitai_api_key',
|
||||||
'default_lora_root',
|
'default_lora_root',
|
||||||
'default_checkpoint_root',
|
'default_checkpoint_root',
|
||||||
'default_embedding_root',
|
'default_embedding_root',
|
||||||
'base_model_path_mappings',
|
'base_model_path_mappings',
|
||||||
'download_path_templates',
|
'download_path_templates',
|
||||||
|
'enable_metadata_archive_db',
|
||||||
|
'language',
|
||||||
'proxy_enabled',
|
'proxy_enabled',
|
||||||
'proxy_type',
|
'proxy_type',
|
||||||
'proxy_host',
|
'proxy_host',
|
||||||
@@ -133,30 +205,38 @@ export class SettingsManager {
|
|||||||
'proxy_username',
|
'proxy_username',
|
||||||
'proxy_password'
|
'proxy_password'
|
||||||
];
|
];
|
||||||
|
return backendKeys.includes(settingKey);
|
||||||
|
}
|
||||||
|
|
||||||
// Build payload for syncing
|
// Helper method to save setting based on whether it's frontend or backend
|
||||||
const payload = {};
|
async saveSetting(settingKey, value) {
|
||||||
|
// Update state
|
||||||
|
state.global.settings[settingKey] = value;
|
||||||
|
|
||||||
fieldsToSync.forEach(key => {
|
if (this.isBackendSetting(settingKey)) {
|
||||||
if (localSettings[key] !== undefined) {
|
// Save to backend
|
||||||
payload[key] = localSettings[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Only send request if there is something to sync
|
|
||||||
if (Object.keys(payload).length > 0) {
|
|
||||||
try {
|
try {
|
||||||
await fetch('/api/settings', {
|
const payload = {};
|
||||||
|
payload[settingKey] = value;
|
||||||
|
|
||||||
|
const response = await fetch('/api/settings', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
});
|
});
|
||||||
// Log success to console
|
|
||||||
console.log('Settings synced to backend');
|
if (!response.ok) {
|
||||||
} catch (e) {
|
throw new Error('Failed to save setting to backend');
|
||||||
// Log error to console
|
}
|
||||||
console.error('Failed to sync settings to backend:', e);
|
} catch (error) {
|
||||||
|
console.error(`Failed to save backend setting ${settingKey}:`, error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Save frontend settings to localStorage
|
||||||
|
this.saveFrontendSettingsToStorage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,23 +683,8 @@ export class SettingsManager {
|
|||||||
|
|
||||||
async saveBaseModelMappings() {
|
async saveBaseModelMappings() {
|
||||||
try {
|
try {
|
||||||
// Save to localStorage
|
// Save to backend using universal save method
|
||||||
setStorageItem('settings', state.global.settings);
|
await this.saveSetting('base_model_path_mappings', state.global.settings.base_model_path_mappings);
|
||||||
|
|
||||||
// Save to backend
|
|
||||||
const response = await fetch('/api/settings', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
base_model_path_mappings: state.global.settings.base_model_path_mappings
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to save base model mappings');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show success toast
|
// Show success toast
|
||||||
const mappingCount = Object.keys(state.global.settings.base_model_path_mappings).length;
|
const mappingCount = Object.keys(state.global.settings.base_model_path_mappings).length;
|
||||||
@@ -793,23 +858,8 @@ export class SettingsManager {
|
|||||||
|
|
||||||
async saveDownloadPathTemplates() {
|
async saveDownloadPathTemplates() {
|
||||||
try {
|
try {
|
||||||
// Save to localStorage
|
// Save to backend using universal save method
|
||||||
setStorageItem('settings', state.global.settings);
|
await this.saveSetting('download_path_templates', state.global.settings.download_path_templates);
|
||||||
|
|
||||||
// Save to backend
|
|
||||||
const response = await fetch('/api/settings', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
download_path_templates: state.global.settings.download_path_templates
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to save download path templates');
|
|
||||||
}
|
|
||||||
|
|
||||||
showToast('toast.settings.downloadTemplatesUpdated', {}, 'success');
|
showToast('toast.settings.downloadTemplatesUpdated', {}, 'success');
|
||||||
|
|
||||||
@@ -834,61 +884,40 @@ export class SettingsManager {
|
|||||||
|
|
||||||
const value = element.checked;
|
const value = element.checked;
|
||||||
|
|
||||||
// Update frontend state
|
|
||||||
if (settingKey === 'blur_mature_content') {
|
|
||||||
state.global.settings.blurMatureContent = value;
|
|
||||||
} else if (settingKey === 'show_only_sfw') {
|
|
||||||
state.global.settings.show_only_sfw = value;
|
|
||||||
} else if (settingKey === 'autoplay_on_hover') {
|
|
||||||
state.global.settings.autoplayOnHover = value;
|
|
||||||
} else if (settingKey === 'optimize_example_images') {
|
|
||||||
state.global.settings.optimizeExampleImages = value;
|
|
||||||
} else if (settingKey === 'auto_download_example_images') {
|
|
||||||
state.global.settings.autoDownloadExampleImages = value;
|
|
||||||
} else if (settingKey === 'compact_mode') {
|
|
||||||
state.global.settings.compactMode = value;
|
|
||||||
} else if (settingKey === 'include_trigger_words') {
|
|
||||||
state.global.settings.includeTriggerWords = value;
|
|
||||||
} else if (settingKey === 'enable_metadata_archive_db') {
|
|
||||||
state.global.settings.enable_metadata_archive_db = value;
|
|
||||||
} else if (settingKey === 'proxy_enabled') {
|
|
||||||
state.global.settings.proxy_enabled = value;
|
|
||||||
|
|
||||||
// Toggle visibility of proxy settings group
|
|
||||||
const proxySettingsGroup = document.getElementById('proxySettingsGroup');
|
|
||||||
if (proxySettingsGroup) {
|
|
||||||
proxySettingsGroup.style.display = value ? 'block' : 'none';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For any other settings that might be added in the future
|
|
||||||
state.global.settings[settingKey] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save to localStorage
|
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// For backend settings, make API call
|
// Update frontend state with mapped keys
|
||||||
if (['show_only_sfw', 'enable_metadata_archive_db', 'proxy_enabled'].includes(settingKey)) {
|
if (settingKey === 'blur_mature_content') {
|
||||||
const payload = {};
|
await this.saveSetting('blurMatureContent', value);
|
||||||
payload[settingKey] = value;
|
} else if (settingKey === 'show_only_sfw') {
|
||||||
|
await this.saveSetting('show_only_sfw', value);
|
||||||
|
} else if (settingKey === 'autoplay_on_hover') {
|
||||||
|
await this.saveSetting('autoplayOnHover', value);
|
||||||
|
} else if (settingKey === 'optimize_example_images') {
|
||||||
|
await this.saveSetting('optimizeExampleImages', value);
|
||||||
|
} else if (settingKey === 'auto_download_example_images') {
|
||||||
|
await this.saveSetting('autoDownloadExampleImages', value);
|
||||||
|
} else if (settingKey === 'compact_mode') {
|
||||||
|
await this.saveSetting('compactMode', value);
|
||||||
|
} else if (settingKey === 'include_trigger_words') {
|
||||||
|
await this.saveSetting('includeTriggerWords', value);
|
||||||
|
} else if (settingKey === 'enable_metadata_archive_db') {
|
||||||
|
await this.saveSetting('enable_metadata_archive_db', value);
|
||||||
|
} else if (settingKey === 'proxy_enabled') {
|
||||||
|
await this.saveSetting('proxy_enabled', value);
|
||||||
|
|
||||||
const response = await fetch('/api/settings', {
|
// Toggle visibility of proxy settings group
|
||||||
method: 'POST',
|
const proxySettingsGroup = document.getElementById('proxySettingsGroup');
|
||||||
headers: {
|
if (proxySettingsGroup) {
|
||||||
'Content-Type': 'application/json',
|
proxySettingsGroup.style.display = value ? 'block' : 'none';
|
||||||
},
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to save setting');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh metadata archive status when enable setting changes
|
|
||||||
if (settingKey === 'enable_metadata_archive_db') {
|
|
||||||
await this.updateMetadataArchiveStatus();
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// For any other settings that might be added in the future
|
||||||
|
await this.saveSetting(settingKey, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh metadata archive status when enable setting changes
|
||||||
|
if (settingKey === 'enable_metadata_archive_db') {
|
||||||
|
await this.updateMetadataArchiveStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
|
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
|
||||||
@@ -933,55 +962,31 @@ export class SettingsManager {
|
|||||||
|
|
||||||
const value = element.value;
|
const value = element.value;
|
||||||
|
|
||||||
// Update frontend state
|
|
||||||
if (settingKey === 'default_lora_root') {
|
|
||||||
state.global.settings.default_lora_root = value;
|
|
||||||
} else if (settingKey === 'default_checkpoint_root') {
|
|
||||||
state.global.settings.default_checkpoint_root = value;
|
|
||||||
} else if (settingKey === 'default_embedding_root') {
|
|
||||||
state.global.settings.default_embedding_root = value;
|
|
||||||
} else if (settingKey === 'display_density') {
|
|
||||||
state.global.settings.displayDensity = value;
|
|
||||||
|
|
||||||
// Also update compactMode for backwards compatibility
|
|
||||||
state.global.settings.compactMode = (value !== 'default');
|
|
||||||
} else if (settingKey === 'card_info_display') {
|
|
||||||
state.global.settings.cardInfoDisplay = value;
|
|
||||||
} else if (settingKey === 'proxy_type') {
|
|
||||||
state.global.settings.proxy_type = value;
|
|
||||||
} else {
|
|
||||||
// For any other settings that might be added in the future
|
|
||||||
state.global.settings[settingKey] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save to localStorage
|
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// For backend settings, make API call
|
// Update frontend state with mapped keys
|
||||||
if (settingKey === 'default_lora_root' || settingKey === 'default_checkpoint_root' || settingKey === 'default_embedding_root' || settingKey === 'download_path_templates' || settingKey.startsWith('proxy_')) {
|
if (settingKey === 'default_lora_root') {
|
||||||
const payload = {};
|
await this.saveSetting('default_lora_root', value);
|
||||||
if (settingKey === 'download_path_templates') {
|
} else if (settingKey === 'default_checkpoint_root') {
|
||||||
payload[settingKey] = state.global.settings.download_path_templates;
|
await this.saveSetting('default_checkpoint_root', value);
|
||||||
} else {
|
} else if (settingKey === 'default_embedding_root') {
|
||||||
payload[settingKey] = value;
|
await this.saveSetting('default_embedding_root', value);
|
||||||
}
|
} else if (settingKey === 'display_density') {
|
||||||
|
await this.saveSetting('displayDensity', value);
|
||||||
|
|
||||||
const response = await fetch('/api/settings', {
|
// Also update compactMode for backwards compatibility
|
||||||
method: 'POST',
|
state.global.settings.compactMode = (value !== 'default');
|
||||||
headers: {
|
this.saveFrontendSettingsToStorage();
|
||||||
'Content-Type': 'application/json',
|
} else if (settingKey === 'card_info_display') {
|
||||||
},
|
await this.saveSetting('cardInfoDisplay', value);
|
||||||
body: JSON.stringify(payload)
|
} else if (settingKey === 'proxy_type') {
|
||||||
});
|
await this.saveSetting('proxy_type', value);
|
||||||
|
} else {
|
||||||
if (!response.ok) {
|
// For any other settings that might be added in the future
|
||||||
throw new Error('Failed to save setting');
|
await this.saveSetting(settingKey, value);
|
||||||
}
|
|
||||||
|
|
||||||
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
|
||||||
|
|
||||||
// Apply frontend settings immediately
|
// Apply frontend settings immediately
|
||||||
this.applyFrontendSettings();
|
this.applyFrontendSettings();
|
||||||
|
|
||||||
@@ -1167,9 +1172,8 @@ export class SettingsManager {
|
|||||||
|
|
||||||
showToast('settings.metadataArchive.downloadSuccess', 'success');
|
showToast('settings.metadataArchive.downloadSuccess', 'success');
|
||||||
|
|
||||||
// Update settings in state
|
// Update settings using universal save method
|
||||||
state.global.settings.enable_metadata_archive_db = true;
|
await this.saveSetting('enable_metadata_archive_db', true);
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
const enableCheckbox = document.getElementById('enableMetadataArchive');
|
const enableCheckbox = document.getElementById('enableMetadataArchive');
|
||||||
@@ -1223,9 +1227,8 @@ export class SettingsManager {
|
|||||||
if (data.success) {
|
if (data.success) {
|
||||||
showToast('settings.metadataArchive.removeSuccess', 'success');
|
showToast('settings.metadataArchive.removeSuccess', 'success');
|
||||||
|
|
||||||
// Update settings in state
|
// Update settings using universal save method
|
||||||
state.global.settings.enable_metadata_archive_db = false;
|
await this.saveSetting('enable_metadata_archive_db', false);
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
const enableCheckbox = document.getElementById('enableMetadataArchive');
|
const enableCheckbox = document.getElementById('enableMetadataArchive');
|
||||||
@@ -1255,7 +1258,6 @@ export class SettingsManager {
|
|||||||
|
|
||||||
const value = element.value.trim(); // Trim whitespace
|
const value = element.value.trim(); // Trim whitespace
|
||||||
|
|
||||||
// For API key or other inputs that need to be saved on backend
|
|
||||||
try {
|
try {
|
||||||
// Check if value has changed from existing value
|
// Check if value has changed from existing value
|
||||||
const currentValue = state.global.settings[settingKey] || '';
|
const currentValue = state.global.settings[settingKey] || '';
|
||||||
@@ -1263,27 +1265,14 @@ export class SettingsManager {
|
|||||||
return; // No change, exit early
|
return; // No change, exit early
|
||||||
}
|
}
|
||||||
|
|
||||||
// For username and password, remove the setting if value is empty
|
// For username and password, handle empty values specially
|
||||||
if ((settingKey === 'proxy_username' || settingKey === 'proxy_password') && value === '') {
|
if ((settingKey === 'proxy_username' || settingKey === 'proxy_password') && value === '') {
|
||||||
// Remove from state instead of setting to empty string
|
// Remove from state instead of setting to empty string
|
||||||
delete state.global.settings[settingKey];
|
delete state.global.settings[settingKey];
|
||||||
} else {
|
|
||||||
// Update state with value (including empty strings for non-optional fields)
|
|
||||||
state.global.settings[settingKey] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
|
|
||||||
// For backend settings, make API call
|
|
||||||
if (settingKey === 'civitai_api_key' || settingKey.startsWith('proxy_')) {
|
|
||||||
const payload = {};
|
|
||||||
|
|
||||||
// For username and password, send delete flag if empty to remove from backend
|
// Send delete flag to backend
|
||||||
if ((settingKey === 'proxy_username' || settingKey === 'proxy_password') && value === '') {
|
const payload = {};
|
||||||
payload[settingKey] = '__DELETE__';
|
payload[settingKey] = '__DELETE__';
|
||||||
} else {
|
|
||||||
payload[settingKey] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch('/api/settings', {
|
const response = await fetch('/api/settings', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -1294,8 +1283,11 @@ export class SettingsManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to save setting');
|
throw new Error('Failed to delete setting');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Use the universal save method
|
||||||
|
await this.saveSetting(settingKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
|
showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success');
|
||||||
@@ -1312,26 +1304,8 @@ export class SettingsManager {
|
|||||||
const selectedLanguage = element.value;
|
const selectedLanguage = element.value;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Update local state
|
// Use the universal save method for language (frontend-only setting)
|
||||||
state.global.settings.language = selectedLanguage;
|
await this.saveSetting('language', selectedLanguage);
|
||||||
|
|
||||||
// Save to localStorage
|
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
|
|
||||||
// Save to backend
|
|
||||||
const response = await fetch('/api/settings', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
language: selectedLanguage
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to save language setting to backend');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload the page to apply the new language
|
// Reload the page to apply the new language
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
|||||||
@@ -2,11 +2,17 @@
|
|||||||
import { getStorageItem, getMapFromStorage } from '../utils/storageHelpers.js';
|
import { getStorageItem, getMapFromStorage } from '../utils/storageHelpers.js';
|
||||||
import { MODEL_TYPES } from '../api/apiConfig.js';
|
import { MODEL_TYPES } from '../api/apiConfig.js';
|
||||||
|
|
||||||
// Load settings from localStorage or use defaults
|
// Load only frontend settings from localStorage with defaults
|
||||||
|
// Backend settings will be loaded by SettingsManager from the backend
|
||||||
const savedSettings = getStorageItem('settings', {
|
const savedSettings = getStorageItem('settings', {
|
||||||
blurMatureContent: true,
|
blurMatureContent: true,
|
||||||
show_only_sfw: false,
|
show_only_sfw: false,
|
||||||
cardInfoDisplay: 'always'
|
cardInfoDisplay: 'always',
|
||||||
|
autoplayOnHover: false,
|
||||||
|
displayDensity: 'default',
|
||||||
|
optimizeExampleImages: true,
|
||||||
|
autoDownloadExampleImages: true,
|
||||||
|
includeTriggerWords: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load preview versions from localStorage for each model type
|
// Load preview versions from localStorage for each model type
|
||||||
|
|||||||
Reference in New Issue
Block a user