mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-24 06:21:26 -03:00
fix(recipes): show initialization screen and auto-reload during first scan
The recipes page always rendered with is_initializing=False, so a cold start displayed an empty grid that never updated until a manual refresh. Mirror the model pages: gate render_page on the scanner state, broadcast init progress from RecipeScanner (including a completion message, and a failure fallback so the page never stalls), and teach initialization.js to detect the /loras/recipes page before the generic /loras match.
This commit is contained in:
@@ -176,11 +176,19 @@ class RecipePageView:
|
||||
user_language = self._settings.get("language", "en")
|
||||
self._server_i18n.set_locale(user_language)
|
||||
|
||||
# While the initial scan is running, show the initialization
|
||||
# screen (same as the model pages) instead of an empty grid; the
|
||||
# page reloads itself when the scanner broadcasts completion.
|
||||
is_initializing = (
|
||||
recipe_scanner._cache is None or recipe_scanner.is_initializing()
|
||||
)
|
||||
|
||||
try:
|
||||
await recipe_scanner.get_cached_data(force_refresh=False)
|
||||
if not is_initializing:
|
||||
await recipe_scanner.get_cached_data(force_refresh=False)
|
||||
rendered = self._template_env.get_template(self._template_name).render(
|
||||
recipes=[],
|
||||
is_initializing=False,
|
||||
is_initializing=is_initializing,
|
||||
settings=self._settings,
|
||||
request=request,
|
||||
t=self._server_i18n.get_translation,
|
||||
|
||||
@@ -19,6 +19,7 @@ from ..utils.recipe_open_stats import RecipeOpenStats
|
||||
from .model_scanner import WEIGHT_FILE_EXTENSIONS
|
||||
from .recipe_cache import RecipeCache
|
||||
from .recipes.errors import RecipeNotFoundError, RecipePersistenceError
|
||||
from .websocket_manager import ws_manager
|
||||
from natsort import natsorted
|
||||
import sys
|
||||
import re
|
||||
@@ -481,6 +482,10 @@ class RecipeScanner:
|
||||
return str(value)
|
||||
return "unknown"
|
||||
|
||||
def is_initializing(self) -> bool:
|
||||
"""Check if the scanner is currently initializing"""
|
||||
return self._is_initializing
|
||||
|
||||
def on_library_changed(self) -> None:
|
||||
"""Reset cached state when the active library changes."""
|
||||
|
||||
@@ -1410,6 +1415,14 @@ class RecipeScanner:
|
||||
self._is_initializing = True
|
||||
self._initialization_task = asyncio.current_task()
|
||||
try:
|
||||
await ws_manager.broadcast_init_progress({
|
||||
'stage': 'loading_cache',
|
||||
'progress': 0,
|
||||
'details': 'Loading recipe cache...',
|
||||
'scanner_type': 'recipe',
|
||||
'pageType': 'recipes',
|
||||
})
|
||||
|
||||
await self._wait_for_lora_scanner()
|
||||
|
||||
# Set initial empty cache to avoid None reference errors
|
||||
@@ -1442,11 +1455,38 @@ class RecipeScanner:
|
||||
logger.info(
|
||||
f"Recipe cache initialized in {elapsed_time:.2f} seconds. Found {recipe_count} recipes"
|
||||
)
|
||||
await ws_manager.broadcast_init_progress({
|
||||
'stage': 'finalizing',
|
||||
'progress': 100,
|
||||
'status': 'complete',
|
||||
'details': f'Found {recipe_count} recipes.',
|
||||
'scanner_type': 'recipe',
|
||||
'pageType': 'recipes',
|
||||
})
|
||||
self._schedule_post_scan_enrichment()
|
||||
# Schedule FTS index build in background (non-blocking)
|
||||
self._schedule_fts_index_build()
|
||||
except Exception as e:
|
||||
logger.error(f"Recipe Scanner: Error initializing cache in background: {e}")
|
||||
# Ensure the cache is never None so the page stops showing the
|
||||
# initialization screen, and let waiting clients reload into the
|
||||
# regular (possibly empty) view instead of stalling.
|
||||
if self._cache is None:
|
||||
self._cache = RecipeCache(
|
||||
raw_data=[],
|
||||
sorted_by_name=[],
|
||||
sorted_by_date=[],
|
||||
folders=[],
|
||||
folder_tree={},
|
||||
)
|
||||
await ws_manager.broadcast_init_progress({
|
||||
'stage': 'finalizing',
|
||||
'progress': 100,
|
||||
'status': 'complete',
|
||||
'details': 'Recipe cache initialization failed.',
|
||||
'scanner_type': 'recipe',
|
||||
'pageType': 'recipes',
|
||||
})
|
||||
finally:
|
||||
# Mark initialization as complete regardless of outcome
|
||||
self._is_initializing = False
|
||||
|
||||
@@ -52,7 +52,11 @@ class InitializationManager {
|
||||
detectPageType() {
|
||||
// Get the current page type from URL or data attribute
|
||||
const path = window.location.pathname;
|
||||
if (path.includes('/checkpoints')) {
|
||||
// The recipes page lives at /loras/recipes, so it must be matched
|
||||
// before the generic '/loras' check.
|
||||
if (path.includes('/recipes')) {
|
||||
this.pageType = 'recipes';
|
||||
} else if (path.includes('/checkpoints')) {
|
||||
this.pageType = 'checkpoints';
|
||||
} else if (path.includes('/loras')) {
|
||||
this.pageType = 'loras';
|
||||
@@ -216,7 +220,8 @@ class InitializationManager {
|
||||
const scannerTypeToPageType = {
|
||||
'lora': 'loras',
|
||||
'checkpoint': 'checkpoints',
|
||||
'embedding': 'embeddings'
|
||||
'embedding': 'embeddings',
|
||||
'recipe': 'recipes'
|
||||
};
|
||||
|
||||
if (scannerTypeToPageType[data.scanner_type] !== this.pageType) {
|
||||
|
||||
Reference in New Issue
Block a user