Skip to content

Commit de051ed

Browse files
committed
fix(ui): stop tweak cards from spinning on Checking forever
The backend detect scan began emitting tweak-status events before the frontend had built its tweak list, so the earliest events were dropped silently by setStatusView and loadModel then reset every status to a fresh loading placeholder. Nothing re-sent them, leaving the first few tweaks in corpus order stuck on Checking for the life of the session. Await initializeQuick() before starting the stream (Svelte mounts +page before +layout, so loadRemainingData kicked the scan first), and buffer any status view that still arrives ahead of its tweak so loadModel seeds from it instead of overwriting it.
1 parent 8eb7bc6 commit de051ed

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

src/lib/stores/tweaksData.svelte.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ function mapStatusView(tweakId: string, view: TweakStatusView): TweakStatus {
110110
};
111111
}
112112

113+
/**
114+
* Status views that arrived before their tweak existed in `tweaks`. The scan thread can outrun
115+
* `loadModel`, and without this the event would be dropped and the card would spin forever.
116+
*/
117+
let pendingStatusViews: Record<string, TweakStatusView> = {};
118+
113119
// Derived: tweaks grouped by category
114120
const tweaksByCategory = $derived.by(() => {
115121
const byCategory: Record<string, TweakWithStatus[]> = {};
@@ -363,7 +369,14 @@ export const tweaksStore = {
363369
try {
364370
const [views, cats] = await Promise.all([api.getTweaks(), api.getCategories()]);
365371
categoryMeta = cats;
366-
tweaks = views.map((v) => ({ definition: mapView(v), status: loadingStatus(v.id) }));
372+
tweaks = views.map((v) => {
373+
const early = pendingStatusViews[v.id];
374+
return {
375+
definition: mapView(v),
376+
status: early ? mapStatusView(v.id, early) : loadingStatus(v.id),
377+
};
378+
});
379+
pendingStatusViews = {};
367380
tweaksVersion++;
368381
return tweaks;
369382
} catch (error) {
@@ -377,6 +390,10 @@ export const tweaksStore = {
377390

378391
/** Replace a tweak's status from a freshly detected engine status view. */
379392
setStatusView(tweakId: string, view: TweakStatusView) {
393+
if (!tweaks.some((t) => t.definition.id === tweakId)) {
394+
pendingStatusViews[tweakId] = view;
395+
return;
396+
}
380397
tweaks = tweaks.map((t) => (t.definition.id === tweakId ? { ...t, status: mapStatusView(tweakId, view) } : t));
381398
},
382399

@@ -479,6 +496,10 @@ export async function initializeQuick(): Promise<void> {
479496
/**
480497
* Load remaining data after quick init: system info, elevation state, and the
481498
* background-progressive status stream (statuses fill in incrementally).
499+
*
500+
* The model load is awaited first, not assumed: Svelte mounts `+page` before `+layout`, so this
501+
* runs before the layout's `initializeQuick()` and would otherwise kick the scan against an empty
502+
* `tweaks` array (the call is promise-cached, so it joins the layout's load rather than repeating it).
482503
*/
483504
export async function loadRemainingData(): Promise<void> {
484505
if (remainingDataPromise) {
@@ -488,7 +509,8 @@ export async function loadRemainingData(): Promise<void> {
488509
return;
489510
}
490511

491-
remainingDataPromise = Promise.all([systemStore.load(), elevationStore.load(), startStatusStream()])
512+
remainingDataPromise = initializeQuick()
513+
.then(() => Promise.all([systemStore.load(), elevationStore.load(), startStatusStream()]))
492514
.then(() => {
493515
initialLoadComplete = true;
494516
})

0 commit comments

Comments
 (0)