From 0da5894529b199643de4a6e2c7455711c6e6ba71 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Wed, 11 Mar 2026 19:01:21 -0400 Subject: [PATCH] fix: stable WS client ID + presentation name for poster modal title - Generate and persist crypto.randomUUID() as controller_client_id on first launcher load (events_loc is persisted so it survives page reloads). Previously fell back to Date.now() on every reload. - ae_open: handler now resolves presentation name via Dexie lookup chain: file.for_id -> presentation.name, falling back to file.filename. Remote modal now shows the presentation title instead of raw filename. --- .../(launcher)/launcher/+layout.svelte | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/routes/events/[event_id]/(launcher)/launcher/+layout.svelte b/src/routes/events/[event_id]/(launcher)/launcher/+layout.svelte index 43a02b0f..f7875893 100644 --- a/src/routes/events/[event_id]/(launcher)/launcher/+layout.svelte +++ b/src/routes/events/[event_id]/(launcher)/launcher/+layout.svelte @@ -78,6 +78,15 @@ }; } + // Generate a stable per-device client ID on first load and persist it. + // events_loc is backed by svelte-persisted-store (localStorage) so this + // survives page reloads. Without this, client_id falls back to Date.now() + // inside element_websocket_v3 — a new ID on every reload, which breaks + // direct-target WS messages and doesn't match V3 Vision ID expectations. + if (!$events_loc.launcher.controller_client_id) { + $events_loc.launcher.controller_client_id = crypto.randomUUID(); + } + // Unified Selection Sync (Refactored 2026-02-11) // WHY: We track URL params directly to ensure the UI reacts instantly to navigation. // We use untrack for store writes to prevent circular dependency loops. @@ -342,10 +351,16 @@ $events_sess.launcher.modal__open_event_file_id = obj_id; // Look up the file object from Dexie so the modal can render the image. // The remote device has no event_file_obj in scope — only the ID was sent over WS. - db_events.file.get(obj_id).then((file_obj: any) => { + // Also look up the parent presentation to use its name as the modal title + // (cleaner for the LCD display than a raw filename). + db_events.file.get(obj_id).then(async (file_obj: any) => { if (file_obj) { $events_sess.launcher.modal__event_file_obj = file_obj; - $events_sess.launcher.modal__title = file_obj.filename ?? ''; + const presentation = file_obj.for_id + ? await db_events.presentation.get(file_obj.for_id) + : null; + $events_sess.launcher.modal__title = + presentation?.name ?? file_obj.filename ?? ''; } }); }