From d43041755e1fd4766ef25dad5660e4e8ea3d4e5c Mon Sep 17 00:00:00 2001 From: Kevin Cantrell Date: Wed, 20 May 2026 22:57:14 +0900 Subject: [PATCH] fixed issue here locations and devices, as well as gorups were not loading at login --- .../dashboard/DashboardCards.svelte | 28 +++++++++++++++---- src/routes/+page.svelte | 27 +++++++++++------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/lib/components/dashboard/DashboardCards.svelte b/src/lib/components/dashboard/DashboardCards.svelte index 4f2bb266..4446d94f 100644 --- a/src/lib/components/dashboard/DashboardCards.svelte +++ b/src/lib/components/dashboard/DashboardCards.svelte @@ -65,6 +65,15 @@ console.debug('[dashboard] loadPage skipped — already loading'); return; } + // On a fresh login (new tab) the auth token can still be undefined when + // this component first mounts. Stay in the loading state instead of + // fetching with no token (which yields an empty "no devices" view) — the + // effect below re-runs once app.accessToken becomes available. + if (!app.accessToken) { + if (opts.reset) reloading = true; + console.debug('[dashboard] loadPage deferred — auth token not ready'); + return; + } loading = true; reloading = !!opts.reset; const skip = opts.reset ? 0 : groups.length; @@ -188,11 +197,20 @@ } $effect(() => { - // Track ONLY filter values so this effect re-runs exclusively on filter change, - // never on internal state writes from loadPage itself. - const _filterFingerprint = - filters.group + '|' + filters.locationGroup + '|' + filters.location + '|' + filters.name; - void _filterFingerprint; + // Track filter values AND the auth token so this effect re-runs on filter + // change and once the token arrives after a fresh login — never on internal + // state writes from loadPage itself. + const _loadFingerprint = + (app.accessToken ?? '') + + '|' + + filters.group + + '|' + + filters.locationGroup + + '|' + + filters.location + + '|' + + filters.name; + void _loadFingerprint; untrack(() => { loadPage({ reset: true }); }); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 2b95b182..0633c747 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -43,17 +43,24 @@ view = 'cards'; } viewReady = true; + }); - // Populate the sidebar's location-group filter list. Cheap aggregate endpoint. - if (app.accessToken) { - const api = new ApiService({ authToken: app.accessToken }); - api.getLocationGroups().then((groups) => { - app.locationGroups = groups; - }).catch(() => { /* sidebar tolerates an empty list */ }); - api.getLocations().then((locations) => { - app.locations = locations; - }).catch(() => { /* sidebar tolerates an empty list */ }); - } + // Populate the sidebar's location-group filter list. Cheap aggregate endpoint. + // Runs as an effect (not onMount) because on a fresh login the auth token can + // still be undefined at mount — the effect re-runs once app.accessToken + // arrives. The guard keeps it to a single fetch. + let sidebarDataLoaded = false; + $effect(() => { + const token = app.accessToken; + if (!token || sidebarDataLoaded) return; + sidebarDataLoaded = true; + const api = new ApiService({ authToken: token }); + api.getLocationGroups().then((groups) => { + app.locationGroups = groups; + }).catch(() => { /* sidebar tolerates an empty list */ }); + api.getLocations().then((locations) => { + app.locations = locations; + }).catch(() => { /* sidebar tolerates an empty list */ }); });