Refactor storage handling across application

- Introduced a new storageHelpers module to centralize localStorage interactions, improving code maintainability and readability.
- Updated various components and managers to utilize the new storageHelpers functions for setting, getting, and removing items from localStorage.
- Added migration logic to handle localStorage items during application initialization, ensuring compatibility with the new storage structure.
- Enhanced logging during application initialization for better debugging.
This commit is contained in:
Will Miao
2025-03-22 05:32:18 +08:00
parent bb3d73b87c
commit 19ef73a07f
11 changed files with 169 additions and 27 deletions

View File

@@ -0,0 +1,22 @@
from typing import Dict, Any
from .base_processor import NodeProcessor, register_processor
@register_processor
class FluxGuidanceProcessor(NodeProcessor):
"""Processor for Flux Guidance nodes"""
NODE_CLASS_TYPE = "FluxGuidance"
REQUIRED_FIELDS = {"guidance"}
def process(self, workflow_parser) -> Dict[str, Any]:
"""Process a FluxGuidance node to extract guidance value"""
result = {}
positive_text = self.resolve_input("conditioning", workflow_parser)
if positive_text:
result["positive"] = positive_text
if "guidance" in self.inputs:
result["guidance"] = str(self.inputs["guidance"])
return result

View File

@@ -1,6 +1,7 @@
import { refreshSingleLoraMetadata } from '../api/loraApi.js'; import { refreshSingleLoraMetadata } from '../api/loraApi.js';
import { showToast, getNSFWLevelName } from '../utils/uiHelpers.js'; import { showToast, getNSFWLevelName } from '../utils/uiHelpers.js';
import { NSFW_LEVELS } from '../utils/constants.js'; import { NSFW_LEVELS } from '../utils/constants.js';
import { getStorageItem } from '../utils/storageHelpers.js';
export class LoraContextMenu { export class LoraContextMenu {
constructor() { constructor() {
@@ -149,7 +150,7 @@ export class LoraContextMenu {
updateCardBlurEffect(card, level) { updateCardBlurEffect(card, level) {
// Get user settings for blur threshold // Get user settings for blur threshold
const blurThreshold = parseInt(localStorage.getItem('nsfwBlurLevel') || '4'); const blurThreshold = parseInt(getStorageItem('nsfwBlurLevel') || '4');
// Get card preview container // Get card preview container
const previewContainer = card.querySelector('.card-preview'); const previewContainer = card.querySelector('.card-preview');

View File

@@ -7,6 +7,7 @@ import { HeaderManager } from './components/Header.js';
import { SettingsManager } from './managers/SettingsManager.js'; import { SettingsManager } from './managers/SettingsManager.js';
import { showToast, initTheme, initBackToTop, lazyLoadImages } from './utils/uiHelpers.js'; import { showToast, initTheme, initBackToTop, lazyLoadImages } from './utils/uiHelpers.js';
import { initializeInfiniteScroll } from './utils/infiniteScroll.js'; import { initializeInfiniteScroll } from './utils/infiniteScroll.js';
import { migrateStorageItems } from './utils/storageHelpers.js';
// Core application class // Core application class
export class AppCore { export class AppCore {
@@ -18,6 +19,8 @@ export class AppCore {
async initialize() { async initialize() {
if (this.initialized) return; if (this.initialized) return;
console.log('AppCore: Initializing...');
// Initialize managers // Initialize managers
state.loadingManager = new LoadingManager(); state.loadingManager = new LoadingManager();
modalManager.initialize(); modalManager.initialize();
@@ -64,6 +67,11 @@ export class AppCore {
} }
} }
document.addEventListener('DOMContentLoaded', () => {
// Migrate localStorage items to use the namespace prefix
migrateStorageItems();
});
// Create and export a singleton instance // Create and export a singleton instance
export const appCore = new AppCore(); export const appCore = new AppCore();

View File

@@ -1,5 +1,5 @@
import { appCore } from './core.js'; import { appCore } from './core.js';
import { state, initPageState } from './state/index.js'; import { state } from './state/index.js';
import { showLoraModal, toggleShowcase, scrollToTop } from './components/LoraModal.js'; import { showLoraModal, toggleShowcase, scrollToTop } from './components/LoraModal.js';
import { loadMoreLoras, fetchCivitai, deleteModel, replacePreview, resetAndReload, refreshLoras } from './api/loraApi.js'; import { loadMoreLoras, fetchCivitai, deleteModel, replacePreview, resetAndReload, refreshLoras } from './api/loraApi.js';
import { import {
@@ -97,9 +97,6 @@ function initializeEventListeners() {
// Initialize everything when DOM is ready // Initialize everything when DOM is ready
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
// Initialize page state
initPageState('loras');
// Initialize core application // Initialize core application
await appCore.initialize(); await appCore.initialize();

View File

@@ -2,6 +2,7 @@ import { BASE_MODELS, BASE_MODEL_CLASSES } from '../utils/constants.js';
import { state, getCurrentPageState } from '../state/index.js'; import { state, getCurrentPageState } from '../state/index.js';
import { showToast, updatePanelPositions } from '../utils/uiHelpers.js'; import { showToast, updatePanelPositions } from '../utils/uiHelpers.js';
import { loadMoreLoras } from '../api/loraApi.js'; import { loadMoreLoras } from '../api/loraApi.js';
import { removeStorageItem, setStorageItem, getStorageItem } from '../utils/storageHelpers.js';
export class FilterManager { export class FilterManager {
constructor(options = {}) { constructor(options = {}) {
@@ -267,7 +268,7 @@ export class FilterManager {
const storageKey = `${this.currentPage}_filters`; const storageKey = `${this.currentPage}_filters`;
// Save filters to localStorage // Save filters to localStorage
localStorage.setItem(storageKey, JSON.stringify(this.filters)); setStorageItem(storageKey, this.filters);
// Update state with current filters // Update state with current filters
pageState.filters = { ...this.filters }; pageState.filters = { ...this.filters };
@@ -323,9 +324,9 @@ export class FilterManager {
this.updateTagSelections(); this.updateTagSelections();
this.updateActiveFiltersCount(); this.updateActiveFiltersCount();
// Remove from localStorage // Remove from local Storage
const storageKey = `${this.currentPage}_filters`; const storageKey = `${this.currentPage}_filters`;
localStorage.removeItem(storageKey); removeStorageItem(storageKey);
// Update UI // Update UI
this.filterButton.classList.remove('active'); this.filterButton.classList.remove('active');
@@ -344,16 +345,14 @@ export class FilterManager {
loadFiltersFromStorage() { loadFiltersFromStorage() {
const storageKey = `${this.currentPage}_filters`; const storageKey = `${this.currentPage}_filters`;
const savedFilters = localStorage.getItem(storageKey); const savedFilters = getStorageItem(storageKey);
if (savedFilters) { if (savedFilters) {
try { try {
const parsedFilters = JSON.parse(savedFilters);
// Ensure backward compatibility with older filter format // Ensure backward compatibility with older filter format
this.filters = { this.filters = {
baseModel: parsedFilters.baseModel || [], baseModel: savedFilters.baseModel || [],
tags: parsedFilters.tags || [] tags: savedFilters.tags || []
}; };
// Update state with loaded filters // Update state with loaded filters

View File

@@ -1,5 +1,6 @@
import { updatePanelPositions } from "../utils/uiHelpers.js"; import { updatePanelPositions } from "../utils/uiHelpers.js";
import { getCurrentPageState } from "../state/index.js"; import { getCurrentPageState } from "../state/index.js";
import { setStorageItem, getStorageItem } from "../utils/storageHelpers.js";
/** /**
* SearchManager - Handles search functionality across different pages * SearchManager - Handles search functionality across different pages
* Each page can extend or customize this base functionality * Each page can extend or customize this base functionality
@@ -183,7 +184,7 @@ export class SearchManager {
loadSearchPreferences() { loadSearchPreferences() {
try { try {
const preferences = JSON.parse(localStorage.getItem(`${this.currentPage}_search_prefs`)) || {}; const preferences = getStorageItem(`${this.currentPage}_search_prefs`) || {};
// Apply search options // Apply search options
if (preferences.options) { if (preferences.options) {
@@ -254,7 +255,7 @@ export class SearchManager {
preferences.recursive = this.recursiveSearchToggle.checked; preferences.recursive = this.recursiveSearchToggle.checked;
} }
localStorage.setItem(`${this.currentPage}_search_prefs`, JSON.stringify(preferences)); setStorageItem(`${this.currentPage}_search_prefs`, preferences);
} catch (error) { } catch (error) {
console.error('Error saving search preferences:', error); console.error('Error saving search preferences:', error);
} }

View File

@@ -2,6 +2,7 @@ import { modalManager } from './ModalManager.js';
import { showToast } from '../utils/uiHelpers.js'; import { showToast } from '../utils/uiHelpers.js';
import { state } from '../state/index.js'; import { state } from '../state/index.js';
import { resetAndReload } from '../api/loraApi.js'; import { resetAndReload } from '../api/loraApi.js';
import { setStorageItem } from '../utils/storageHelpers.js';
export class SettingsManager { export class SettingsManager {
constructor() { constructor() {
@@ -75,7 +76,7 @@ export class SettingsManager {
state.global.settings.show_only_sfw = showOnlySFW; state.global.settings.show_only_sfw = showOnlySFW;
// Save settings to localStorage // Save settings to localStorage
localStorage.setItem('settings', JSON.stringify(state.global.settings)); setStorageItem('settings', state.global.settings);
try { try {
// Save backend settings via API // Save backend settings via API

View File

@@ -1,4 +1,5 @@
import { modalManager } from './ModalManager.js'; import { modalManager } from './ModalManager.js';
import { getStorageItem, setStorageItem } from '../utils/storageHelpers.js';
export class UpdateService { export class UpdateService {
constructor() { constructor() {
@@ -7,13 +8,13 @@ export class UpdateService {
this.latestVersion = "v0.0.0"; // Initialize with default values this.latestVersion = "v0.0.0"; // Initialize with default values
this.updateInfo = null; this.updateInfo = null;
this.updateAvailable = false; this.updateAvailable = false;
this.updateNotificationsEnabled = localStorage.getItem('show_update_notifications') !== 'false'; this.updateNotificationsEnabled = getStorageItem('show_update_notifications') !== 'false';
this.lastCheckTime = parseInt(localStorage.getItem('last_update_check') || '0'); this.lastCheckTime = parseInt(getStorageItem('last_update_check') || '0');
} }
initialize() { initialize() {
// Initialize update preferences from localStorage // Initialize update preferences from localStorage
const showUpdates = localStorage.getItem('show_update_notifications'); const showUpdates = getStorageItem('show_update_notifications');
this.updateNotificationsEnabled = showUpdates === null || showUpdates === 'true'; this.updateNotificationsEnabled = showUpdates === null || showUpdates === 'true';
// Register event listener for update notification toggle // Register event listener for update notification toggle
@@ -22,7 +23,7 @@ export class UpdateService {
updateCheckbox.checked = this.updateNotificationsEnabled; updateCheckbox.checked = this.updateNotificationsEnabled;
updateCheckbox.addEventListener('change', (e) => { updateCheckbox.addEventListener('change', (e) => {
this.updateNotificationsEnabled = e.target.checked; this.updateNotificationsEnabled = e.target.checked;
localStorage.setItem('show_update_notifications', e.target.checked); setStorageItem('show_update_notifications', e.target.checked);
this.updateBadgeVisibility(); this.updateBadgeVisibility();
}); });
} }
@@ -71,7 +72,7 @@ export class UpdateService {
// Update last check time // Update last check time
this.lastCheckTime = now; this.lastCheckTime = now;
localStorage.setItem('last_update_check', now.toString()); setStorageItem('last_update_check', now.toString());
// Update UI // Update UI
this.updateBadgeVisibility(); this.updateBadgeVisibility();

View File

@@ -0,0 +1,110 @@
/**
* Utility functions for localStorage with namespacing to avoid conflicts
* with other ComfyUI extensions or the main application
*/
// Namespace prefix for all localStorage keys
const STORAGE_PREFIX = 'lora_manager_';
/**
* Get an item from localStorage with namespace support and fallback to legacy keys
* @param {string} key - The key without prefix
* @param {any} defaultValue - Default value if key doesn't exist
* @returns {any} The stored value or defaultValue
*/
export function getStorageItem(key, defaultValue = null) {
// Try with prefix first
const prefixedValue = localStorage.getItem(STORAGE_PREFIX + key);
if (prefixedValue !== null) {
// If it's a JSON string, parse it
try {
return JSON.parse(prefixedValue);
} catch (e) {
return prefixedValue;
}
}
// Fallback to legacy key (without prefix)
const legacyValue = localStorage.getItem(key);
if (legacyValue !== null) {
// If found in legacy storage, migrate it to prefixed storage
try {
const parsedValue = JSON.parse(legacyValue);
setStorageItem(key, parsedValue);
return parsedValue;
} catch (e) {
setStorageItem(key, legacyValue);
return legacyValue;
}
}
// Return default value if neither prefixed nor legacy key exists
return defaultValue;
}
/**
* Set an item in localStorage with namespace prefix
* @param {string} key - The key without prefix
* @param {any} value - The value to store
*/
export function setStorageItem(key, value) {
const prefixedKey = STORAGE_PREFIX + key;
// Convert objects and arrays to JSON strings
if (typeof value === 'object' && value !== null) {
localStorage.setItem(prefixedKey, JSON.stringify(value));
} else {
localStorage.setItem(prefixedKey, value);
}
}
/**
* Remove an item from localStorage (both prefixed and legacy)
* @param {string} key - The key without prefix
*/
export function removeStorageItem(key) {
localStorage.removeItem(STORAGE_PREFIX + key);
localStorage.removeItem(key); // Also remove legacy key
}
/**
* Migrate all existing localStorage items to use the prefix
* This should be called once during application initialization
*/
export function migrateStorageItems() {
// List of known keys used in the application
const knownKeys = [
'nsfwBlurLevel',
'theme',
'activeFolder',
'folderTagsCollapsed',
'settings',
'loras_filters',
'recipes_filters',
'checkpoints_filters',
'loras_search_prefs',
'recipes_search_prefs',
'checkpoints_search_prefs',
'show_update_notifications',
'last_update_check'
];
// Migrate each known key
knownKeys.forEach(key => {
const value = localStorage.getItem(key);
if (value !== null) {
try {
// Try to parse as JSON first
const parsedValue = JSON.parse(value);
setStorageItem(key, parsedValue);
} catch (e) {
// If not JSON, store as is
setStorageItem(key, value);
}
}
});
console.log('Lora Manager: Storage migration completed');
}

View File

@@ -1,5 +1,6 @@
import { state } from '../state/index.js'; import { state } from '../state/index.js';
import { resetAndReload } from '../api/loraApi.js'; import { resetAndReload } from '../api/loraApi.js';
import { getStorageItem, setStorageItem } from './storageHelpers.js';
export function showToast(message, type = 'info') { export function showToast(message, type = 'info') {
const toast = document.createElement('div'); const toast = document.createElement('div');
@@ -27,7 +28,7 @@ export function lazyLoadImages() {
} }
export function restoreFolderFilter() { export function restoreFolderFilter() {
const activeFolder = localStorage.getItem('activeFolder'); const activeFolder = getStorageItem('activeFolder');
const folderTag = activeFolder && document.querySelector(`.tag[data-folder="${activeFolder}"]`); const folderTag = activeFolder && document.querySelector(`.tag[data-folder="${activeFolder}"]`);
if (folderTag) { if (folderTag) {
folderTag.classList.add('active'); folderTag.classList.add('active');
@@ -36,13 +37,13 @@ export function restoreFolderFilter() {
} }
export function initTheme() { export function initTheme() {
document.body.dataset.theme = localStorage.getItem('theme') || 'dark'; document.body.dataset.theme = getStorageItem('theme') || 'dark';
} }
export function toggleTheme() { export function toggleTheme() {
const theme = document.body.dataset.theme === 'light' ? 'dark' : 'light'; const theme = document.body.dataset.theme === 'light' ? 'dark' : 'light';
document.body.dataset.theme = theme; document.body.dataset.theme = theme;
localStorage.setItem('theme', theme); setStorageItem('theme', theme);
} }
export function toggleFolder(tag) { export function toggleFolder(tag) {
@@ -158,12 +159,12 @@ export function toggleFolderTags() {
// Change icon to indicate folders are hidden // Change icon to indicate folders are hidden
toggleBtn.className = 'fas fa-folder-plus'; toggleBtn.className = 'fas fa-folder-plus';
toggleBtn.parentElement.title = 'Show folder tags'; toggleBtn.parentElement.title = 'Show folder tags';
localStorage.setItem('folderTagsCollapsed', 'true'); setStorageItem('folderTagsCollapsed', 'true');
} else { } else {
// Change icon to indicate folders are visible // Change icon to indicate folders are visible
toggleBtn.className = 'fas fa-folder-minus'; toggleBtn.className = 'fas fa-folder-minus';
toggleBtn.parentElement.title = 'Hide folder tags'; toggleBtn.parentElement.title = 'Hide folder tags';
localStorage.setItem('folderTagsCollapsed', 'false'); setStorageItem('folderTagsCollapsed', 'false');
} }
// Update panel positions after toggling // Update panel positions after toggling
@@ -176,7 +177,7 @@ export function toggleFolderTags() {
// Add this to your existing initialization code // Add this to your existing initialization code
export function initFolderTagsVisibility() { export function initFolderTagsVisibility() {
const isCollapsed = localStorage.getItem('folderTagsCollapsed') === 'true'; const isCollapsed = getStorageItem('folderTagsCollapsed') === 'true';
if (isCollapsed) { if (isCollapsed) {
const folderTags = document.querySelector('.folder-tags'); const folderTags = document.querySelector('.folder-tags');
const toggleBtn = document.querySelector('.toggle-folders-btn i'); const toggleBtn = document.querySelector('.toggle-folders-btn i');

View File

@@ -771,6 +771,7 @@ async function saveRecipeDirectly(widget) {
try { try {
// Get the workflow data from the ComfyUI app // Get the workflow data from the ComfyUI app
const prompt = await app.graphToPrompt(); const prompt = await app.graphToPrompt();
console.log('Prompt:', prompt.output);
// Show loading toast // Show loading toast
if (app && app.extensionManager && app.extensionManager.toast) { if (app && app.extensionManager && app.extensionManager.toast) {