Fix: Event session cold-start bug - presentations/presenters now load on first render

CRITICAL BUG FIX: Session view required 1-2 manual refreshes to display
presentations and presenters when IndexedDB was empty.

Root Cause:
- Nested loaders passed try_cache: false, preventing IDB writes
- Missing microtask yields caused race conditions between IDB writes
  and liveQuery subscriptions

Changes:
- ae_events__event_session.ts: Preserve try_cache in nested loads
- ae_events__event_presentation.ts: Block on presenter loads with await
  Promise.all() + preserve try_cache
- ae_events__event_presenter.ts: Add microtask yield after IDB write

Result: Presentations AND presenters now render correctly on first
navigation without requiring manual page refresh.
This commit is contained in:
Scott Idem
2026-02-26 13:40:36 -05:00
parent 9da3e5326b
commit 3849118fec
3 changed files with 49 additions and 28 deletions

View File

@@ -184,11 +184,20 @@ async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_
if (try_cache) { if (try_cache) {
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: processed, properties_to_save, log_lvl }); await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: processed, properties_to_save, log_lvl });
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
// fire before we return. Without this, component-mounted liveQueries may subscribe
// to IDB *before* the write completes, causing empty results on cold-start.
await Promise.resolve();
}
// CRITICAL FIX (2026-02-26): Block on nested loads when explicitly requested.
// Previously fire-and-forget (forEach without await), which meant the function returned
// before presenter data was loaded, causing "refresh twice" bug on cold-start.
// Now we await all nested loads AND preserve try_cache so presenters are written to IDB.
if (inc_file_li || inc_presenter_li) {
await Promise.all(processed.map(p =>
_handle_nested_loads(p, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 })
));
} }
// Background nested loads for refreshed items (FIRE AND FORGET)
processed.forEach(p => {
_handle_nested_loads(p, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache: false, log_lvl: 0 });
});
return processed; return processed;
} }
} catch (e) {} } catch (e) {}

View File

@@ -153,6 +153,10 @@ async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj
if (try_cache) { if (try_cache) {
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: processed, properties_to_save, log_lvl }); await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: processed, properties_to_save, log_lvl });
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
// fire before we return. Without this, component-mounted liveQueries may subscribe
// to IDB *before* the write completes, causing empty results on cold-start.
await Promise.resolve();
} }
// Background nested loads for refreshed items (FIRE AND FORGET) // Background nested loads for refreshed items (FIRE AND FORGET)

View File

@@ -99,9 +99,17 @@ async function _refresh_session_id_background({ api_cfg, event_session_id, view,
if (try_cache) { if (try_cache) {
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: [processed_obj], properties_to_save, log_lvl }); await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: [processed_obj], properties_to_save, log_lvl });
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
// fire before we return. Without this, component-mounted liveQueries may subscribe
// to IDB *before* the write completes, causing empty results on cold-start.
await Promise.resolve();
if (log_lvl) console.log(`💾 [Trace] _refresh_session_id: Saved to IDB cache.`); if (log_lvl) console.log(`💾 [Trace] _refresh_session_id: Saved to IDB cache.`);
} }
return await _handle_nested_loads(processed_obj, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache: false, log_lvl }); // CRITICAL FIX (2026-02-26): Preserve parent's try_cache value when loading nested data.
// Previously set to `false`, which meant presentations/presenters were fetched from API
// but NEVER written to IndexedDB, causing "refresh twice" bug on cold-start.
// Now nested loads inherit parent's caching behavior for deterministic first-render.
return await _handle_nested_loads(processed_obj, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl });
} }
} catch (e) { } catch (e) {
if (log_lvl) console.error(`❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`, e); if (log_lvl) console.error(`❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`, e);