launcher: fix liveQuery reactivity for location-dependent queries

The three liveQueries that depend on $events_slct.event_location_id were
plain liveQuery() calls, not $derived.by(() => liveQuery(...)). This meant
Svelte store changes did NOT cause them to re-run.

Root cause of the 'hung' bug:
- On initial load at /launcher (no location in URL), id = null
- Dexie watches the event_location_id = null index range
- User selects a location (or navigates to /launcher/{id}): store updates
- Sessions for the real location are in a DIFFERENT Dexie range
- Dexie never fires because the null range was never touched
- If sessions are already in IndexedDB cache (no new DB write), the list
  stays permanently frozen at []

Fix: convert lq__event_session_obj_li, lq__location_event_file_obj_li, and
lq__event_location_obj to $derived.by(() => liveQuery(...)). When
event_location_id changes, $derived.by creates a new Observable targeting
the correct location, which immediately queries Dexie for existing cached
data and then watches that range for further changes.

Also: remove the .reverse() before .sortBy('name') on the session query —
.sortBy() always re-sorts so .reverse() before it was a no-op.
This commit is contained in:
Scott Idem
2026-03-06 21:51:31 -05:00
parent 589ab9b652
commit 3447c4d4a4

View File

@@ -181,20 +181,28 @@
});
// Event File - For Location
let lq__location_event_file_obj_li = liveQuery(async () => {
// $derived.by: must recreate the observable when event_location_id changes.
// Plain liveQuery() only re-fires when Dexie detects a change in the initially
// watched index range — if the id starts as null and changes to a real value,
// Dexie never fires because a different range was added (not the null range).
let lq__location_event_file_obj_li = $derived.by(() => {
const id = $events_slct.event_location_id;
if (!id) return [];
return await db_events.file
.where('for_id')
.equals(id)
.sortBy('filename');
return liveQuery(async () => {
if (!id) return [];
return await db_events.file
.where('for_id')
.equals(id)
.sortBy('filename');
});
});
// Event Location
let lq__event_location_obj = liveQuery(async () => {
// Event Location — same reason as above
let lq__event_location_obj = $derived.by(() => {
const id = $events_slct.event_location_id;
if (!id) return null;
return await db_events.location.get(id);
return liveQuery(async () => {
if (!id) return null;
return await db_events.location.get(id);
});
});
let lq__event_location_obj_li = liveQuery(async () => {
@@ -206,27 +214,30 @@
.sortBy('name');
});
let lq__event_session_obj_li = liveQuery(async () => {
// $derived.by: must recreate when event_location_id changes (see comment above).
let lq__event_session_obj_li = $derived.by(() => {
const id = $events_slct.event_location_id;
if (!id) return [];
if (log_lvl > 1)
console.log(
`LQ - Using default sort for Event Session list location_id: ${id}`
);
let results = await db_events.session
.where('event_location_id')
.equals(id)
.reverse()
.sortBy('name');
return liveQuery(async () => {
if (!id) return [];
if (log_lvl > 1)
console.log(
`LQ - Event Session list location_id: ${id}`
);
// Note: .reverse() before .sortBy() is a no-op — sortBy always re-sorts.
let results = await db_events.session
.where('event_location_id')
.equals(id)
.sortBy('name');
if (
$events_slct.event_session_obj_li &&
JSON.stringify($events_slct.event_session_obj_li) !==
JSON.stringify(results)
) {
$events_slct.event_session_obj_li = [...(results || [])];
}
return results;
if (
$events_slct.event_session_obj_li &&
JSON.stringify($events_slct.event_session_obj_li) !==
JSON.stringify(results)
) {
$events_slct.event_session_obj_li = [...(results || [])];
}
return results;
});
});
// Event Session (Main View Trigger - Needed for Global Header/Idle)