diff --git a/js/entry.js b/js/entry.js index 0746da64..78aa3ce0 100644 --- a/js/entry.js +++ b/js/entry.js @@ -166,10 +166,13 @@ app.registerExtension({ void checkMajoorVersion(); - // Get ComfyUI API - const api = (await waitForComfyApi({ app: runtimeApp, timeoutMs: 4000 })) || getComfyApi(runtimeApp); - setComfyApi(api || null); - if (api) { + // Initialize API listeners in the background so sidebar tab registration + // is not blocked by API readiness polling. + void (async () => { + // Get ComfyUI API + const api = (await waitForComfyApi({ app: runtimeApp, timeoutMs: 4000 })) || getComfyApi(runtimeApp); + setComfyApi(api || null); + if (api) { let runtime = null; try { runtime = typeof window !== "undefined" ? (window[ENTRY_RUNTIME_KEY] || null) : null; @@ -353,6 +356,7 @@ app.registerExtension({ } else { console.warn("📂 Majoor [⚠️] API not available, real-time updates disabled"); } + })(); // Register sidebar tab if (registerSidebarTabCompat(runtimeApp, { diff --git a/js/features/grid/GridView_impl.js b/js/features/grid/GridView_impl.js index 5a29aa94..59fdace8 100644 --- a/js/features/grid/GridView_impl.js +++ b/js/features/grid/GridView_impl.js @@ -96,7 +96,7 @@ const RT_HYDRATE_STATE = new WeakMap(); // gridContainer -> { queue, inflight, s // ───────────────────────────────────────────────────────────────────────────── // Upsert Batching - Accumulate upserts and flush once for performance // ───────────────────────────────────────────────────────────────────────────── -const UPSERT_BATCH_DEBOUNCE_MS = 50; // Debounce window for batch flush +const UPSERT_BATCH_DEBOUNCE_MS = 200; // Debounce window for batch flush const UPSERT_BATCH_MAX_SIZE = 50; // Max items before forced flush const UPSERT_BATCH_STATE = new WeakMap(); // gridContainer -> { pending: Map, timer: number|null } diff --git a/js/features/panel/AssetsManagerPanel.js b/js/features/panel/AssetsManagerPanel.js index 3e3310b0..291e0242 100644 --- a/js/features/panel/AssetsManagerPanel.js +++ b/js/features/panel/AssetsManagerPanel.js @@ -1243,7 +1243,11 @@ export async function renderAssetsManager(container, { useComfyThemeUI = true } lastKnownIndexEnd = counters.last_index_end; return; } - if (!hasNewScan && !hasNewIndexEnd && !hasNewTotal) return; + // hasNewIndexEnd alone does NOT trigger a full reload: the backend pushes + // mjr-asset-added immediately after index_paths, which handles it via upsert. + // A full reload would flash the loading overlay over already-visible assets. + if (hasNewIndexEnd) lastKnownIndexEnd = counters.last_index_end; + if (!hasNewScan && !hasNewTotal) return; // Global throttle against reload storms from frequent watcher/enrichment updates. try { diff --git a/mjr_am_backend/features/index/service.py b/mjr_am_backend/features/index/service.py index 185723bb..06163fd9 100644 --- a/mjr_am_backend/features/index/service.py +++ b/mjr_am_backend/features/index/service.py @@ -206,6 +206,21 @@ class IndexService: PromptServer.instance.send_sync("mjr-scan-complete", res.data) except Exception as e: logger.debug("Failed to emit scan-complete event: %s", e) + # Push newly-added assets immediately so the frontend can upsert them + # into the grid without waiting for the next polling cycle. + added_ids = (res.data or {}).get("added_ids") or [] + if added_ids: + try: + from ...routes.registry import PromptServer + batch_res = await self.get_assets_batch(list(added_ids[:20])) + if batch_res.ok and batch_res.data: + for asset in batch_res.data: + try: + PromptServer.instance.send_sync("mjr-asset-added", dict(asset)) + except Exception: + pass + except Exception as e: + logger.debug("Failed to emit mjr-asset-added events: %s", e) mark_directory_indexed(base_dir, source, root_id) return res