From f8fe4ac5a2502e6d053330c1dbc4e6329a32c330 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 12 May 2026 13:37:11 -0400 Subject: [PATCH] fix(launcher): button state hygiene across all 3 modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix 1 (stale error_detail): open_file_error_detail is now cleared at the start of every mode's branch (native, onsite, default) alongside open_file_clicked=true. Previously it was cleared mid-way through the native flow (Step 1), so a stale error from a previous failed run could flash briefly. Fix 2 (stuck 'Opening...' during post_script sleep): After the Step 4 open call returns (run_cmd or open_local_file_v2), update the status message immediately to 'App opened — running setup...' so the button doesn't appear frozen for the full post_delay_ms wait. Fix 3 (safety valve for hanging native calls): A 60s setTimeout is registered at the start of the native branch. If any native IPC call hangs indefinitely and the existing per-path reset timeouts never fire, this force-resets open_file_clicked after 60s. All normal paths complete within ~8s so this only triggers on true hangs. ERR_NETWORK_CHANGED cannot re-enter the download path because the open_file_clicked guard blocks re-entry. --- .../(launcher)/launcher_file_cont.svelte | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/routes/events/[event_id]/(launcher)/launcher_file_cont.svelte b/src/routes/events/[event_id]/(launcher)/launcher_file_cont.svelte index 209c423a..ebd5451a 100644 --- a/src/routes/events/[event_id]/(launcher)/launcher_file_cont.svelte +++ b/src/routes/events/[event_id]/(launcher)/launcher_file_cont.svelte @@ -277,6 +277,17 @@ async function handle_open_file() { open_file_clicked = true; open_file_status = 'checking_cache'; open_file_status_message = 'Checking local cache...'; + open_file_error_detail = null; // Fix 1: clear stale error from any previous attempt + + // Fix 2: safety valve — if a native call hangs and no path resets the button, + // force-release it after 60s. All normal paths reset within ~8s so this is last resort. + setTimeout(() => { + if (open_file_clicked) { + open_file_clicked = false; + open_file_status = 'error'; + open_file_status_message = 'Timed out — please try again'; + } + }, 60_000); const exists = await native.check_hash_file_cache({ cache_root, @@ -364,6 +375,14 @@ async function handle_open_file() { } } + // Fix 3: update the status message as soon as the open call returns so "Opening..." doesn't + // appear stuck for the entire post_script sleep. OS has the request; we're just waiting now. + if (open_ok) { + open_file_status_message = profile.post_script + ? `${profile.app} opened — running setup...` + : `${profile.app} opened`; + } + // --- Step 5: Wait for app to load before running post-script --- // Only delay if there is actually a post_script to run — no point waiting for nothing. if (open_ok && profile.post_script) { @@ -426,6 +445,7 @@ async function handle_open_file() { open_file_clicked = true; open_file_status = 'downloading_onsite'; open_file_status_message = 'Downloading (Onsite Mode)...'; + open_file_error_detail = null; let filename = event_file_obj.filename; if ( @@ -457,6 +477,7 @@ async function handle_open_file() { open_file_clicked = true; open_file_status = 'downloading_default'; open_file_status_message = 'Downloading...'; + open_file_error_detail = null; const dl_promise = api.get_object({ api_cfg: $ae_api,