From 710857dd4153032970c622e8e46219f24fd40147 Mon Sep 17 00:00:00 2001 From: Will Miao <13051207myq@gmail.com> Date: Mon, 17 Mar 2025 19:58:17 +0800 Subject: [PATCH] checkpoint --- static/js/common.js | 16 -- static/js/components/Header.js | 1 + static/js/components/LoraModal.js | 1 + static/js/core.js | 64 ++++++++ static/js/loras.js | 107 ++++++++++++++ static/js/main.js | 125 ---------------- static/js/managers/MoveManager.js | 1 + static/js/recipes.js | 43 +++--- static/js/utils/routes.js | 53 +++++++ templates/base.html | 110 ++++++++++++++ templates/loras.html | 121 +++------------ templates/recipes.html | 235 ++++++++++++------------------ 12 files changed, 470 insertions(+), 407 deletions(-) delete mode 100644 static/js/common.js create mode 100644 static/js/core.js create mode 100644 static/js/loras.js delete mode 100644 static/js/main.js create mode 100644 static/js/utils/routes.js create mode 100644 templates/base.html diff --git a/static/js/common.js b/static/js/common.js deleted file mode 100644 index f0202b73..00000000 --- a/static/js/common.js +++ /dev/null @@ -1,16 +0,0 @@ -import { toggleTheme, initTheme } from './utils/uiHelpers.js'; -import { modalManager } from './managers/ModalManager.js'; -import { updateService } from './managers/UpdateService.js'; -import { SettingsManager } from './managers/SettingsManager.js'; - -// Export common functions -export function initializeCommonComponents() { - modalManager.initialize(); - updateService.initialize(); - initTheme(); - - // Initialize common controls - window.toggleTheme = toggleTheme; - window.modalManager = modalManager; - window.settingsManager = new SettingsManager(); -} diff --git a/static/js/components/Header.js b/static/js/components/Header.js index 2078b132..4c567560 100644 --- a/static/js/components/Header.js +++ b/static/js/components/Header.js @@ -1,4 +1,5 @@ import { updateService } from '../managers/UpdateService.js'; +import { toggleTheme } from '../utils/uiHelpers.js'; /** * Header.js - Manages the application header behavior across different pages diff --git a/static/js/components/LoraModal.js b/static/js/components/LoraModal.js index 635b0ce1..5a333c99 100644 --- a/static/js/components/LoraModal.js +++ b/static/js/components/LoraModal.js @@ -1,5 +1,6 @@ import { showToast } from '../utils/uiHelpers.js'; import { state } from '../state/index.js'; +import { modalManager } from '../managers/ModalManager.js'; import { NSFW_LEVELS } from '../utils/constants.js'; export function showLoraModal(lora) { diff --git a/static/js/core.js b/static/js/core.js new file mode 100644 index 00000000..1560a1b5 --- /dev/null +++ b/static/js/core.js @@ -0,0 +1,64 @@ +// Core application functionality +import { state, initSettings } from './state/index.js'; +import { LoadingManager } from './managers/LoadingManager.js'; +import { modalManager } from './managers/ModalManager.js'; +import { updateService } from './managers/UpdateService.js'; +import { HeaderManager } from './components/Header.js'; +import { SettingsManager } from './managers/SettingsManager.js'; +import { showToast, initTheme, initBackToTop, updatePanelPositions } from './utils/uiHelpers.js'; + +// Core application class +export class AppCore { + constructor() { + this.initialized = false; + } + + // Initialize core functionality + async initialize() { + if (this.initialized) return; + + // Initialize settings + initSettings(); + + // Initialize managers + state.loadingManager = new LoadingManager(); + modalManager.initialize(); + updateService.initialize(); + window.modalManager = modalManager; + window.settingsManager = new SettingsManager(); + + // Initialize UI components + window.headerManager = new HeaderManager(); + initTheme(); + initBackToTop(); + + // Set up event listeners + window.addEventListener('resize', updatePanelPositions); + + // Initial positioning + updatePanelPositions(); + + // Mark as initialized + this.initialized = true; + + // Return the core instance for chaining + return this; + } + + // Get the current page type + getPageType() { + const body = document.body; + return body.dataset.page || 'unknown'; + } + + // Show toast messages + showToast(message, type = 'info') { + showToast(message, type); + } +} + +// Create and export a singleton instance +export const appCore = new AppCore(); + +// Export common utilities for global use +export { showToast, modalManager, state }; \ No newline at end of file diff --git a/static/js/loras.js b/static/js/loras.js new file mode 100644 index 00000000..7f3c0d4c --- /dev/null +++ b/static/js/loras.js @@ -0,0 +1,107 @@ +import { appCore, state } from './core.js'; +import { showLoraModal, toggleShowcase, scrollToTop } from './components/LoraModal.js'; +import { loadMoreLoras, fetchCivitai, deleteModel, replacePreview, resetAndReload, refreshLoras } from './api/loraApi.js'; +import { + lazyLoadImages, + restoreFolderFilter, + toggleFolder, + copyTriggerWord, + openCivitai, + toggleFolderTags, + initFolderTagsVisibility, + updatePanelPositions +} from './utils/uiHelpers.js'; +import { initializeInfiniteScroll } from './utils/infiniteScroll.js'; +import { showDeleteModal, confirmDelete, closeDeleteModal } from './utils/modalUtils.js'; +import { DownloadManager } from './managers/DownloadManager.js'; +import { toggleApiKeyVisibility } from './managers/SettingsManager.js'; +import { LoraContextMenu } from './components/ContextMenu.js'; +import { moveManager } from './managers/MoveManager.js'; +import { createLoraCard, updateCardsForBulkMode } from './components/LoraCard.js'; +import { bulkManager } from './managers/BulkManager.js'; + +// Initialize the LoRA page +class LoraPageManager { + constructor() { + // Add bulk mode to state + state.bulkMode = false; + state.selectedLoras = new Set(); + + // Initialize managers + this.downloadManager = new DownloadManager(); + + // Expose necessary functions to the page + this._exposeGlobalFunctions(); + } + + _exposeGlobalFunctions() { + // Only expose what's needed for the page + window.loadMoreLoras = loadMoreLoras; + window.fetchCivitai = fetchCivitai; + window.deleteModel = deleteModel; + window.replacePreview = replacePreview; + window.toggleFolder = toggleFolder; + window.copyTriggerWord = copyTriggerWord; + window.showLoraModal = showLoraModal; + window.confirmDelete = confirmDelete; + window.closeDeleteModal = closeDeleteModal; + window.refreshLoras = refreshLoras; + window.openCivitai = openCivitai; + window.toggleFolderTags = toggleFolderTags; + window.toggleApiKeyVisibility = toggleApiKeyVisibility; + window.downloadManager = this.downloadManager; + window.moveManager = moveManager; + window.toggleShowcase = toggleShowcase; + window.scrollToTop = scrollToTop; + + // Bulk operations + window.toggleBulkMode = () => bulkManager.toggleBulkMode(); + window.clearSelection = () => bulkManager.clearSelection(); + window.toggleCardSelection = (card) => bulkManager.toggleCardSelection(card); + window.copyAllLorasSyntax = () => bulkManager.copyAllLorasSyntax(); + window.updateSelectedCount = () => bulkManager.updateSelectedCount(); + window.bulkManager = bulkManager; + } + + async initialize() { + // Initialize page-specific components + initializeInfiniteScroll(); + initializeEventListeners(); + lazyLoadImages(); + restoreFolderFilter(); + initFolderTagsVisibility(); + new LoraContextMenu(); + + // Initialize cards for current bulk mode state (should be false initially) + updateCardsForBulkMode(state.bulkMode); + + // Initialize the bulk manager + bulkManager.initialize(); + } +} + +// Initialize event listeners +function initializeEventListeners() { + const sortSelect = document.getElementById('sortSelect'); + if (sortSelect) { + sortSelect.value = state.sortBy; + sortSelect.addEventListener('change', async (e) => { + state.sortBy = e.target.value; + await resetAndReload(); + }); + } + + document.querySelectorAll('.folder-tags .tag').forEach(tag => { + tag.addEventListener('click', toggleFolder); + }); +} + +// Initialize everything when DOM is ready +document.addEventListener('DOMContentLoaded', async () => { + // Initialize core application + await appCore.initialize(); + + // Initialize page-specific functionality + const loraPage = new LoraPageManager(); + await loraPage.initialize(); +}); \ No newline at end of file diff --git a/static/js/main.js b/static/js/main.js deleted file mode 100644 index af0dc77a..00000000 --- a/static/js/main.js +++ /dev/null @@ -1,125 +0,0 @@ -import { debounce } from './utils/debounce.js'; -import { LoadingManager } from './managers/LoadingManager.js'; -import { modalManager } from './managers/ModalManager.js'; -import { updateService } from './managers/UpdateService.js'; -import { state, initSettings } from './state/index.js'; -import { initializeCommonComponents } from './common.js'; -import { showLoraModal } from './components/LoraModal.js'; -import { toggleShowcase, scrollToTop } from './components/LoraModal.js'; -import { loadMoreLoras, fetchCivitai, deleteModel, replacePreview, resetAndReload, refreshLoras } from './api/loraApi.js'; -import { - showToast, - lazyLoadImages, - restoreFolderFilter, - initTheme, - toggleTheme, - toggleFolder, - copyTriggerWord, - openCivitai, - toggleFolderTags, - initFolderTagsVisibility, - initBackToTop, - updatePanelPositions -} from './utils/uiHelpers.js'; -import { initializeInfiniteScroll } from './utils/infiniteScroll.js'; -import { showDeleteModal, confirmDelete, closeDeleteModal } from './utils/modalUtils.js'; -import { DownloadManager } from './managers/DownloadManager.js'; -import { SettingsManager, toggleApiKeyVisibility } from './managers/SettingsManager.js'; -import { LoraContextMenu } from './components/ContextMenu.js'; -import { moveManager } from './managers/MoveManager.js'; -import { createLoraCard, updateCardsForBulkMode } from './components/LoraCard.js'; -import { bulkManager } from './managers/BulkManager.js'; -import { HeaderManager } from './components/Header.js'; -// Add bulk mode to state -state.bulkMode = false; -state.selectedLoras = new Set(); - -// Export functions to global window object -window.loadMoreLoras = loadMoreLoras; -window.fetchCivitai = fetchCivitai; -window.deleteModel = deleteModel; -window.replacePreview = replacePreview; -window.toggleTheme = toggleTheme; -window.toggleFolder = toggleFolder; -window.copyTriggerWord = copyTriggerWord; -window.showLoraModal = showLoraModal; -window.modalManager = modalManager; -window.state = state; -window.confirmDelete = confirmDelete; -window.closeDeleteModal = closeDeleteModal; -window.refreshLoras = refreshLoras; -window.openCivitai = openCivitai; -window.showToast = showToast -window.toggleFolderTags = toggleFolderTags; -window.settingsManager = new SettingsManager(); -window.toggleApiKeyVisibility = toggleApiKeyVisibility; -window.moveManager = moveManager; -window.toggleShowcase = toggleShowcase; -window.scrollToTop = scrollToTop; -window.updatePanelPositions = updatePanelPositions; - -// Export bulk manager methods to window -window.toggleBulkMode = () => bulkManager.toggleBulkMode(); -window.clearSelection = () => bulkManager.clearSelection(); -window.toggleCardSelection = (card) => bulkManager.toggleCardSelection(card); -window.copyAllLorasSyntax = () => bulkManager.copyAllLorasSyntax(); -window.updateSelectedCount = () => bulkManager.updateSelectedCount(); -window.bulkManager = bulkManager; - -// Initialize everything when DOM is ready -document.addEventListener('DOMContentLoaded', async () => { - // Ensure settings are initialized - initSettings(); - - initializeCommonComponents(); - window.headerManager = new HeaderManager(); - state.loadingManager = new LoadingManager(); - modalManager.initialize(); // Initialize modalManager after DOM is loaded - updateService.initialize(); // Initialize updateService after modalManager - window.downloadManager = new DownloadManager(); // Move this after modalManager initialization - - // Initialize state filters from filterManager if available - if (window.filterManager && window.filterManager.filters) { - state.filters = { ...window.filterManager.filters }; - } - - initializeInfiniteScroll(); - initializeEventListeners(); - lazyLoadImages(); - restoreFolderFilter(); - initTheme(); - initFolderTagsVisibility(); - initBackToTop(); - new LoraContextMenu(); - - // Initialize cards for current bulk mode state (should be false initially) - updateCardsForBulkMode(state.bulkMode); - - // Initialize the bulk manager - bulkManager.initialize(); - - // Initial positioning - updatePanelPositions(); - - // Update positions on window resize - window.addEventListener('resize', updatePanelPositions); - - // Set the current page for proper context - document.body.dataset.page = 'loras'; -}); - -// Initialize event listeners -function initializeEventListeners() { - const sortSelect = document.getElementById('sortSelect'); - if (sortSelect) { - sortSelect.value = state.sortBy; - sortSelect.addEventListener('change', async (e) => { - state.sortBy = e.target.value; - await resetAndReload(); - }); - } - - document.querySelectorAll('.folder-tags .tag').forEach(tag => { - tag.addEventListener('click', toggleFolder); - }); -} \ No newline at end of file diff --git a/static/js/managers/MoveManager.js b/static/js/managers/MoveManager.js index c2bb51ea..532066f5 100644 --- a/static/js/managers/MoveManager.js +++ b/static/js/managers/MoveManager.js @@ -1,4 +1,5 @@ import { showToast } from '../utils/uiHelpers.js'; +import { state } from '../state/index.js'; import { resetAndReload } from '../api/loraApi.js'; import { modalManager } from './ModalManager.js'; diff --git a/static/js/recipes.js b/static/js/recipes.js index a4f69589..de5809f8 100644 --- a/static/js/recipes.js +++ b/static/js/recipes.js @@ -1,11 +1,8 @@ // Recipe manager module -import { showToast } from './utils/uiHelpers.js'; -import { state } from './state/index.js'; -import { initializeCommonComponents } from './common.js'; +import { appCore } from './core.js'; import { ImportManager } from './managers/ImportManager.js'; import { RecipeCard } from './components/RecipeCard.js'; import { RecipeModal } from './components/RecipeModal.js'; -import { HeaderManager } from './components/Header.js'; class RecipeManager { constructor() { @@ -19,19 +16,24 @@ class RecipeManager { // Initialize RecipeModal this.recipeModal = new RecipeModal(); - - this.init(); } - init() { + async initialize() { // Initialize event listeners this.initEventListeners(); // Load initial set of recipes - this.loadRecipes(); - - // Set the current page for proper context - document.body.dataset.page = 'recipes'; + await this.loadRecipes(); + + // Expose necessary functions to the page + this._exposeGlobalFunctions(); + } + + _exposeGlobalFunctions() { + // Only expose what's needed for the page + window.recipeManager = this; + window.importRecipes = () => this.importRecipes(); + window.importManager = this.importManager; } initEventListeners() { @@ -103,7 +105,7 @@ class RecipeManager { } catch (error) { console.error('Error loading recipes:', error); - showToast('Failed to load recipes', 'error'); + appCore.showToast('Failed to load recipes', 'error'); } finally { // Hide loading indicator document.body.classList.remove('loading'); @@ -146,18 +148,13 @@ class RecipeManager { } // Initialize components -document.addEventListener('DOMContentLoaded', () => { - initializeCommonComponents(); - window.headerManager = new HeaderManager(); - window.recipeManager = new RecipeManager(); +document.addEventListener('DOMContentLoaded', async () => { + // Initialize core application + await appCore.initialize(); - // Make importRecipes function available globally - window.importRecipes = () => { - window.recipeManager.importRecipes(); - }; - - // Expose ImportManager instance globally for the import modal event handlers - window.importManager = window.recipeManager.importManager; + // Initialize recipe manager + const recipeManager = new RecipeManager(); + await recipeManager.initialize(); }); // Export for use in other modules diff --git a/static/js/utils/routes.js b/static/js/utils/routes.js new file mode 100644 index 00000000..a3b8f859 --- /dev/null +++ b/static/js/utils/routes.js @@ -0,0 +1,53 @@ +// API routes configuration +export const apiRoutes = { + // LoRA routes + loras: { + list: '/api/loras', + detail: (id) => `/api/loras/${id}`, + delete: (id) => `/api/loras/${id}`, + update: (id) => `/api/loras/${id}`, + civitai: (id) => `/api/loras/${id}/civitai`, + download: '/api/download-lora', + move: '/api/move-lora', + scan: '/api/scan-loras' + }, + + // Recipe routes + recipes: { + list: '/api/recipes', + detail: (id) => `/api/recipes/${id}`, + delete: (id) => `/api/recipes/${id}`, + update: (id) => `/api/recipes/${id}`, + analyze: '/api/analyze-recipe-image', + save: '/api/save-recipe' + }, + + // Checkpoint routes + checkpoints: { + list: '/api/checkpoints', + detail: (id) => `/api/checkpoints/${id}`, + delete: (id) => `/api/checkpoints/${id}`, + update: (id) => `/api/checkpoints/${id}` + }, + + // WebSocket routes + ws: { + fetchProgress: (protocol) => `${protocol}://${window.location.host}/ws/fetch-progress` + } +}; + +// Page routes +export const pageRoutes = { + loras: '/loras', + recipes: '/loras/recipes', + checkpoints: '/checkpoints' +}; + +// Helper function to get current page type +export function getCurrentPageType() { + const path = window.location.pathname; + if (path.includes('/loras/recipes')) return 'recipes'; + if (path.includes('/checkpoints')) return 'checkpoints'; + if (path.includes('/loras')) return 'loras'; + return 'unknown'; +} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 00000000..4815232a --- /dev/null +++ b/templates/base.html @@ -0,0 +1,110 @@ + + + + + {% block title %}LoRA Manager{% endblock %} + + + {% block page_css %}{% endblock %} + + + + + + + + {% block preload %}{% endblock %} + + + + + + + + + + + + + + + + + {% block head_scripts %}{% endblock %} + + + + {% include 'components/header.html' %} + +
+ {% include 'components/modals.html' %} + {% include 'components/loading.html' %} + {% include 'components/context_menu.html' %} + {% block additional_components %}{% endblock %} + +
+ {% if is_initializing %} +
+
+
+

{% block init_title %}Initializing{% endblock %}

+

{% block init_message %}Scanning and building cache. This may take a few minutes...{% endblock %} +

+
+
+ {% else %} + {% block content %}{% endblock %} + {% endif %} +
+ + {% block overlay %}{% endblock %} +
+ + {% block main_script %}{% endblock %} + + {% if is_initializing %} + + {% endif %} + + {% block additional_scripts %}{% endblock %} + + + \ No newline at end of file diff --git a/templates/loras.html b/templates/loras.html index 8e905e15..a4c57ce8 100644 --- a/templates/loras.html +++ b/templates/loras.html @@ -1,104 +1,29 @@ - - - - LoRA Manager - - - - - - - - - - - - - - - - - - - - - - - - +{% extends "base.html" %} - - - - {% include 'components/header.html' %} +{% block title %}LoRA Manager{% endblock %} +{% block page_id %}loras{% endblock %} -
- {% include 'components/modals.html' %} - {% include 'components/loading.html' %} - {% include 'components/context_menu.html' %} +{% block preload %} + +{% endblock %} -
- {% if is_initializing %} -
-
-
-

Initializing LoRA Manager

-

Scanning and building LoRA cache. This may take a few minutes...

-
-
- {% else %} - {% include 'components/controls.html' %} - -
- -
- - {% endif %} -
+{% block init_title %}Initializing LoRA Manager{% endblock %} +{% block init_message %}Scanning and building LoRA cache. This may take a few minutes...{% endblock %} +{% block init_check_url %}/api/loras?page=1&page_size=1{% endblock %} - -
+{% block content %} + {% include 'components/controls.html' %} + +
+
+ +{% endblock %} - - {% if is_initializing %} - - {% endif %} - - \ No newline at end of file +{% block overlay %} +
+{% endblock %} + +{% block main_script %} + +{% endblock %} \ No newline at end of file diff --git a/templates/recipes.html b/templates/recipes.html index 60b10b5f..4bee014f 100644 --- a/templates/recipes.html +++ b/templates/recipes.html @@ -1,153 +1,98 @@ - - - - LoRA Recipes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% include 'components/header.html' %} +{% extends "base.html" %} -
- {% include 'components/modals.html' %} - {% include 'components/loading.html' %} - {% include 'components/context_menu.html' %} - {% include 'components/import_modal.html' %} - {% include 'components/recipe_modal.html' %} +{% block title %}LoRA Recipes{% endblock %} +{% block page_id %}recipes{% endblock %} -
- {% if is_initializing %} -
-
-
-

Initializing Recipe Manager

-

Scanning and building recipe cache. This may take a few moments...

-
+{% block page_css %} + + + +{% endblock %} + +{% block preload %} + +{% endblock %} + +{% block additional_components %} +{% include 'components/import_modal.html' %} +{% include 'components/recipe_modal.html' %} +{% endblock %} + +{% block init_title %}Initializing Recipe Manager{% endblock %} +{% block init_message %}Scanning and building recipe cache. This may take a few moments...{% endblock %} +{% block init_check_url %}/api/recipes?page=1&page_size=1{% endblock %} + +{% block content %} + +
+
+
+
- {% else %} - -
-
-
- -
-
-
- - -
- {% if recipes and recipes|length > 0 %} - {% for recipe in recipes %} -
-
R
-
- {{ recipe.title }} -
-
- {% if recipe.base_model %} - - {{ recipe.base_model }} - - {% endif %} -
-
- - - -
-
- -
-
- {% endfor %} - {% else %} -
-

No recipes found

-

Add recipe images to your recipes folder to see them here.

-
- {% endif %} -
- {% endif %}
+ + +
+ {% if recipes and recipes|length > 0 %} + {% for recipe in recipes %} +
+
R
+
+ {{ recipe.title }} +
+
+ {% if recipe.base_model %} + + {{ recipe.base_model }} + + {% endif %} +
+
+ + + +
+
+ +
+
+ {% endfor %} + {% else %} +
+

No recipes found

+

Add recipe images to your recipes folder to see them here.

+
+ {% endif %} +
+{% endblock %} - - {% if is_initializing %} - - {% endif %} +{% block main_script %} + +{% endblock %} - - - \ No newline at end of file + } + +{% endblock %} \ No newline at end of file