From 59fef58ab43293db019df6ccb1b74d84b91ff190 Mon Sep 17 00:00:00 2001 From: rakadu1 Date: Thu, 27 Nov 2025 09:41:07 +0530 Subject: [PATCH] *Goal* Make file caching fire-and-forget so IndexedDB writes do not block parsing and video loading. *Actions* Update the file pipeline code where saveFileWithMetadata(...) is called: Replace await saveFileWithMetadata(...) with a non-blocking call that stores the promise in an array, e.g. cachePromises.push(saveFileWithMetadata(...).catch(e => logWarning(e))). At the end of the pipeline kick off Promise.allSettled(cachePromises) but do not await it before parsing starts; instead log results or show a non-blocking notification on failure. Add a configurable CACHE_BLOCKING boolean flag in config. Default false; if true (special mode) allow blocking for debugging. Add logging and UI notification for cache failures without blocking the pipeline. Convert any alert() on quota errors into a non-blocking modal message or toast. Add unit tests / smoke tests: Simulate slow saveFileWithMetadata() (wrap with artificial delay) and confirm parsing and video loading start immediately without waiting for caching to finish. Simulate a QuotaExceededError and confirm the pipeline continues. *Check list* Replace await saveFileWithMetadata(...) with non-blocking logic. Pipeline starts parsing immediately even when cache save is delayed. Promise.allSettled(cachePromises) is triggered and results logged. UI shows non-blocking notification for cache failures (no alert() popups). Tests simulate slow save and quota errors and pass. --- steps/package-lock.json | 6 ++++++ steps/src/db.js | 3 ++- steps/src/fileLoader.js | 28 ++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 steps/package-lock.json diff --git a/steps/package-lock.json b/steps/package-lock.json new file mode 100644 index 0000000..4a36c79 --- /dev/null +++ b/steps/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "steps", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/steps/src/db.js b/steps/src/db.js index a9dda75..53792e8 100644 --- a/steps/src/db.js +++ b/steps/src/db.js @@ -1,6 +1,7 @@ let db; let dbReadyPromise; let dbReadyResolve; +import { showModal } from "./modal.js"; // Initialize the promise that tracks DB readiness dbReadyPromise = new Promise((resolve) => { @@ -72,7 +73,7 @@ export function saveFileWithMetadata(key, file) { // Gracefully handle errors, especially quota limits transaction.onerror = (event) => { if (event.target.error.name === 'QuotaExceededError') { - alert("Could not cache file: Browser storage quota exceeded. The app will still work for this session."); + showModal("Could not cache file: Browser storage quota exceeded. The app will still work for this session, but files won't be saved for next time."); resolve(); // Resolve anyway to let the app continue without caching } else { console.error(`Error saving file '${key}':`, event.target.error); diff --git a/steps/src/fileLoader.js b/steps/src/fileLoader.js index cb20a23..6ec6db5 100644 --- a/steps/src/fileLoader.js +++ b/steps/src/fileLoader.js @@ -1,4 +1,5 @@ import { appState } from "./state.js"; +import { debugFlags } from "./debug.js"; import { saveFileWithMetadata } from "./db.js"; import { parseVisualizationJson } from "./fileParsers.js"; import { @@ -60,17 +61,33 @@ async function processFilePipeline(jsonFile, videoFile, fromCache) { // 1. Show the unified loading modal. showLoadingModal("Processing files..."); + const cachePromises = []; + // --- PART A: Setup Filenames & Cache (Moved Up) --- if (jsonFile) { appState.jsonFilename = jsonFile.name; localStorage.setItem("jsonFilename", appState.jsonFilename); - if (!fromCache) await saveFileWithMetadata("json", jsonFile); + if (!fromCache) { + const savePromise = saveFileWithMetadata("json", jsonFile).catch((e) => + console.warn(`Non-blocking cache save failed for JSON:`, e) + ); + if (debugFlags.CACHE_BLOCKING) { + await savePromise; + } else { + cachePromises.push(savePromise); + } + } } if (videoFile) { appState.videoFilename = videoFile.name; localStorage.setItem("videoFilename", appState.videoFilename); - if (!fromCache) await saveFileWithMetadata("video", videoFile); + if (!fromCache) { + const savePromise = saveFileWithMetadata("video", videoFile).catch((e) => + console.warn(`Non-blocking cache save failed for Video:`, e) + ); + cachePromises.push(savePromise); + } } // --- PART B: Calculate Offset (Moved Up) --- @@ -137,6 +154,13 @@ async function processFilePipeline(jsonFile, videoFile, fromCache) { // Hide modal updateLoadingModal(100, "Complete!"); setTimeout(hideModal, 300); + + // Log the results of the non-blocking cache operations once they complete. + if (cachePromises.length > 0) { + Promise.allSettled(cachePromises).then((results) => { + console.log("Non-blocking cache operations finished:", results); + }); + } }