mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-26 07:35:44 -03:00
feat: Refactor SidebarManager integration and cleanup methods for improved state management
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { state, getCurrentPageState } from '../state/index.js';
|
import { state, getCurrentPageState } from '../state/index.js';
|
||||||
import { showToast, updateFolderTags } from '../utils/uiHelpers.js';
|
import { showToast } from '../utils/uiHelpers.js';
|
||||||
import { getStorageItem, getSessionItem, saveMapToStorage } from '../utils/storageHelpers.js';
|
import { getStorageItem, getSessionItem, saveMapToStorage } from '../utils/storageHelpers.js';
|
||||||
import {
|
import {
|
||||||
getCompleteApiConfig,
|
getCompleteApiConfig,
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
WS_ENDPOINTS
|
WS_ENDPOINTS
|
||||||
} from './apiConfig.js';
|
} from './apiConfig.js';
|
||||||
import { resetAndReload } from './modelApiFactory.js';
|
import { resetAndReload } from './modelApiFactory.js';
|
||||||
|
import { sidebarManager } from '../components/SidebarManager.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for all model API clients
|
* Abstract base class for all model API clients
|
||||||
@@ -103,15 +104,7 @@ export class BaseModelApiClient {
|
|||||||
pageState.currentPage = pageState.currentPage + 1;
|
pageState.currentPage = pageState.currentPage + 1;
|
||||||
|
|
||||||
if (updateFolders) {
|
if (updateFolders) {
|
||||||
const response = await fetch(this.apiConfig.endpoints.folders);
|
sidebarManager.refresh();
|
||||||
if (response.ok) {
|
|
||||||
const data = await response.json();
|
|
||||||
updateFolderTags(data.folders);
|
|
||||||
} else {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
const errorMsg = errorData && errorData.error ? errorData.error : response.statusText;
|
|
||||||
console.error(`Error getting folders: ${errorMsg}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { getStorageItem, setStorageItem } from '../utils/storageHelpers.js';
|
|||||||
import { getModelApiClient } from '../api/modelApiFactory.js';
|
import { getModelApiClient } from '../api/modelApiFactory.js';
|
||||||
|
|
||||||
export class SidebarManager {
|
export class SidebarManager {
|
||||||
constructor(pageControls) {
|
constructor() {
|
||||||
this.pageControls = pageControls;
|
this.pageControls = null;
|
||||||
this.pageType = pageControls.pageType;
|
this.pageType = null;
|
||||||
this.treeData = {};
|
this.treeData = {};
|
||||||
this.selectedPath = '';
|
this.selectedPath = '';
|
||||||
this.expandedNodes = new Set();
|
this.expandedNodes = new Set();
|
||||||
@@ -17,6 +17,7 @@ export class SidebarManager {
|
|||||||
this.openDropdown = null;
|
this.openDropdown = null;
|
||||||
this.hoverTimeout = null;
|
this.hoverTimeout = null;
|
||||||
this.isHovering = false;
|
this.isHovering = false;
|
||||||
|
this.isInitialized = false;
|
||||||
|
|
||||||
// Bind methods
|
// Bind methods
|
||||||
this.handleTreeClick = this.handleTreeClick.bind(this);
|
this.handleTreeClick = this.handleTreeClick.bind(this);
|
||||||
@@ -29,8 +30,95 @@ export class SidebarManager {
|
|||||||
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
||||||
this.handleHoverAreaEnter = this.handleHoverAreaEnter.bind(this);
|
this.handleHoverAreaEnter = this.handleHoverAreaEnter.bind(this);
|
||||||
this.handleHoverAreaLeave = this.handleHoverAreaLeave.bind(this);
|
this.handleHoverAreaLeave = this.handleHoverAreaLeave.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
this.init();
|
async initialize(pageControls) {
|
||||||
|
// Clean up previous initialization if exists
|
||||||
|
if (this.isInitialized) {
|
||||||
|
this.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pageControls = pageControls;
|
||||||
|
this.pageType = pageControls.pageType;
|
||||||
|
this.apiClient = getModelApiClient();
|
||||||
|
|
||||||
|
// Set initial sidebar state immediately (hidden by default)
|
||||||
|
this.setInitialSidebarState();
|
||||||
|
|
||||||
|
this.setupEventHandlers();
|
||||||
|
this.updateSidebarTitle();
|
||||||
|
this.restoreSidebarState();
|
||||||
|
await this.loadFolderTree();
|
||||||
|
this.restoreSelectedFolder();
|
||||||
|
|
||||||
|
// Apply final state with animation after everything is loaded
|
||||||
|
this.applyFinalSidebarState();
|
||||||
|
|
||||||
|
this.isInitialized = true;
|
||||||
|
console.log(`SidebarManager initialized for ${this.pageType} page`);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if (!this.isInitialized) return;
|
||||||
|
|
||||||
|
// Clear any pending timeouts
|
||||||
|
if (this.hoverTimeout) {
|
||||||
|
clearTimeout(this.hoverTimeout);
|
||||||
|
this.hoverTimeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up event handlers
|
||||||
|
this.removeEventHandlers();
|
||||||
|
|
||||||
|
// Reset state
|
||||||
|
this.pageControls = null;
|
||||||
|
this.pageType = null;
|
||||||
|
this.treeData = {};
|
||||||
|
this.selectedPath = '';
|
||||||
|
this.expandedNodes = new Set();
|
||||||
|
this.openDropdown = null;
|
||||||
|
this.isHovering = false;
|
||||||
|
this.apiClient = null;
|
||||||
|
this.isInitialized = false;
|
||||||
|
|
||||||
|
console.log('SidebarManager cleaned up');
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEventHandlers() {
|
||||||
|
const pinToggleBtn = document.getElementById('sidebarPinToggle');
|
||||||
|
const collapseAllBtn = document.getElementById('sidebarCollapseAll');
|
||||||
|
const folderTree = document.getElementById('sidebarFolderTree');
|
||||||
|
const sidebarBreadcrumbNav = document.getElementById('sidebarBreadcrumbNav');
|
||||||
|
const sidebarHeader = document.getElementById('sidebarHeader');
|
||||||
|
const sidebar = document.getElementById('folderSidebar');
|
||||||
|
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||||
|
|
||||||
|
if (pinToggleBtn) {
|
||||||
|
pinToggleBtn.removeEventListener('click', this.handlePinToggle);
|
||||||
|
}
|
||||||
|
if (collapseAllBtn) {
|
||||||
|
collapseAllBtn.removeEventListener('click', this.handleCollapseAll);
|
||||||
|
}
|
||||||
|
if (folderTree) {
|
||||||
|
folderTree.removeEventListener('click', this.handleTreeClick);
|
||||||
|
}
|
||||||
|
if (sidebarBreadcrumbNav) {
|
||||||
|
sidebarBreadcrumbNav.removeEventListener('click', this.handleBreadcrumbClick);
|
||||||
|
}
|
||||||
|
if (sidebarHeader) {
|
||||||
|
sidebarHeader.removeEventListener('click', this.handleSidebarHeaderClick);
|
||||||
|
}
|
||||||
|
if (sidebar) {
|
||||||
|
sidebar.removeEventListener('mouseenter', this.handleMouseEnter);
|
||||||
|
sidebar.removeEventListener('mouseleave', this.handleMouseLeave);
|
||||||
|
}
|
||||||
|
if (hoverArea) {
|
||||||
|
hoverArea.removeEventListener('mouseenter', this.handleHoverAreaEnter);
|
||||||
|
hoverArea.removeEventListener('mouseleave', this.handleHoverAreaLeave);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove document click handler
|
||||||
|
document.removeEventListener('click', this.handleDocumentClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
@@ -692,45 +780,9 @@ export class SidebarManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
// Clear any pending timeouts
|
this.cleanup();
|
||||||
if (this.hoverTimeout) {
|
}
|
||||||
clearTimeout(this.hoverTimeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up event handlers
|
// Create and export global instance
|
||||||
const pinToggleBtn = document.getElementById('sidebarPinToggle');
|
export const sidebarManager = new SidebarManager();
|
||||||
const collapseAllBtn = document.getElementById('sidebarCollapseAll');
|
|
||||||
const folderTree = document.getElementById('sidebarFolderTree');
|
|
||||||
const sidebarBreadcrumbNav = document.getElementById('sidebarBreadcrumbNav');
|
|
||||||
const sidebarHeader = document.getElementById('sidebarHeader');
|
|
||||||
const sidebar = document.getElementById('folderSidebar');
|
|
||||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
|
||||||
|
|
||||||
if (pinToggleBtn) {
|
|
||||||
pinToggleBtn.removeEventListener('click', this.handlePinToggle);
|
|
||||||
}
|
|
||||||
if (collapseAllBtn) {
|
|
||||||
collapseAllBtn.removeEventListener('click', this.handleCollapseAll);
|
|
||||||
}
|
|
||||||
if (folderTree) {
|
|
||||||
folderTree.removeEventListener('click', this.handleTreeClick);
|
|
||||||
}
|
|
||||||
if (sidebarBreadcrumbNav) {
|
|
||||||
sidebarBreadcrumbNav.removeEventListener('click', this.handleBreadcrumbClick);
|
|
||||||
}
|
|
||||||
if (sidebarHeader) {
|
|
||||||
sidebarHeader.removeEventListener('click', this.handleSidebarHeaderClick);
|
|
||||||
}
|
|
||||||
if (sidebar) {
|
|
||||||
sidebar.removeEventListener('mouseenter', this.handleMouseEnter);
|
|
||||||
sidebar.removeEventListener('mouseleave', this.handleMouseLeave);
|
|
||||||
}
|
|
||||||
if (hoverArea) {
|
|
||||||
hoverArea.removeEventListener('mouseenter', this.handleHoverAreaEnter);
|
|
||||||
hoverArea.removeEventListener('mouseleave', this.handleHoverAreaLeave);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove document click handler
|
|
||||||
document.removeEventListener('click', this.handleDocumentClick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ import { getCurrentPageState, setCurrentPageType } from '../../state/index.js';
|
|||||||
import { getStorageItem, setStorageItem, getSessionItem, setSessionItem } from '../../utils/storageHelpers.js';
|
import { getStorageItem, setStorageItem, getSessionItem, setSessionItem } from '../../utils/storageHelpers.js';
|
||||||
import { showToast } from '../../utils/uiHelpers.js';
|
import { showToast } from '../../utils/uiHelpers.js';
|
||||||
import { SidebarManager } from '../SidebarManager.js';
|
import { SidebarManager } from '../SidebarManager.js';
|
||||||
|
import { sidebarManager } from '../SidebarManager.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PageControls class - Unified control management for model pages
|
* PageControls class - Unified control management for model pages
|
||||||
@@ -24,8 +25,8 @@ export class PageControls {
|
|||||||
// Store API methods
|
// Store API methods
|
||||||
this.api = null;
|
this.api = null;
|
||||||
|
|
||||||
// Initialize sidebar manager
|
// Use global sidebar manager
|
||||||
this.sidebarManager = null;
|
this.sidebarManager = sidebarManager;
|
||||||
|
|
||||||
// Initialize event listeners
|
// Initialize event listeners
|
||||||
this.initEventListeners();
|
this.initEventListeners();
|
||||||
@@ -69,7 +70,7 @@ export class PageControls {
|
|||||||
*/
|
*/
|
||||||
async initSidebarManager() {
|
async initSidebarManager() {
|
||||||
try {
|
try {
|
||||||
this.sidebarManager = new SidebarManager(this);
|
await this.sidebarManager.initialize(this);
|
||||||
console.log('SidebarManager initialized');
|
console.log('SidebarManager initialized');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize SidebarManager:', error);
|
console.error('Failed to initialize SidebarManager:', error);
|
||||||
@@ -440,8 +441,10 @@ export class PageControls {
|
|||||||
* Clean up resources
|
* Clean up resources
|
||||||
*/
|
*/
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this.sidebarManager) {
|
// Note: We don't destroy the global sidebar manager, just clean it up
|
||||||
this.sidebarManager.destroy();
|
// The global instance will be reused for other page controls
|
||||||
|
if (this.sidebarManager && this.sidebarManager.isInitialized) {
|
||||||
|
this.sidebarManager.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import { showToast, updateFolderTags } from '../utils/uiHelpers.js';
|
import { showToast } from '../utils/uiHelpers.js';
|
||||||
import { state, getCurrentPageState } from '../state/index.js';
|
import { state, getCurrentPageState } from '../state/index.js';
|
||||||
import { modalManager } from './ModalManager.js';
|
import { modalManager } from './ModalManager.js';
|
||||||
import { bulkManager } from './BulkManager.js';
|
import { bulkManager } from './BulkManager.js';
|
||||||
import { getStorageItem } from '../utils/storageHelpers.js';
|
import { getStorageItem } from '../utils/storageHelpers.js';
|
||||||
import { getModelApiClient } from '../api/modelApiFactory.js';
|
import { getModelApiClient } from '../api/modelApiFactory.js';
|
||||||
import { FolderTreeManager } from '../components/FolderTreeManager.js';
|
import { FolderTreeManager } from '../components/FolderTreeManager.js';
|
||||||
|
import { sidebarManager } from '../components/SidebarManager.js';
|
||||||
|
|
||||||
class MoveManager {
|
class MoveManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -224,12 +225,7 @@ class MoveManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Refresh folder tags after successful move
|
// Refresh folder tags after successful move
|
||||||
try {
|
sidebarManager.refresh();
|
||||||
const foldersData = await apiClient.fetchModelFolders();
|
|
||||||
updateFolderTags(foldersData.folders);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error refreshing folder tags:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
modalManager.closeModal('moveModal');
|
modalManager.closeModal('moveModal');
|
||||||
|
|
||||||
|
|||||||
@@ -666,31 +666,3 @@ export async function openExampleImagesFolder(modelHash) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the folder tags display with new folder list
|
|
||||||
* @param {Array} folders - List of folder names
|
|
||||||
*/
|
|
||||||
export function updateFolderTags(folders) {
|
|
||||||
const folderTagsContainer = document.querySelector('.folder-tags');
|
|
||||||
if (!folderTagsContainer) return;
|
|
||||||
|
|
||||||
// Keep track of currently selected folder
|
|
||||||
const pageState = getCurrentPageState();
|
|
||||||
const currentFolder = pageState.activeFolder;
|
|
||||||
|
|
||||||
// Create HTML for folder tags
|
|
||||||
const tagsHTML = folders.map(folder => {
|
|
||||||
const isActive = folder === currentFolder;
|
|
||||||
return `<div class="tag ${isActive ? 'active' : ''}" data-folder="${folder}">${folder}</div>`;
|
|
||||||
}).join('');
|
|
||||||
|
|
||||||
// Update the container
|
|
||||||
folderTagsContainer.innerHTML = tagsHTML;
|
|
||||||
|
|
||||||
// Scroll active folder into view (no need to reattach click handlers)
|
|
||||||
const activeTag = folderTagsContainer.querySelector(`.tag[data-folder="${currentFolder}"]`);
|
|
||||||
if (activeTag) {
|
|
||||||
activeTag.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user