mirror of
https://github.com/HeyPuter/puter.git
synced 2026-08-27 16:37:18 +00:00
fix: keep hidden apps' saved ranks through the mid-drag stash path
- _applyPendingLoad reconciled a stashed load against the visible-only on-screen order, tail-appending any app returning to the grid and contradicting the order the drag had just saved — the rank-demotion defect resurfacing through one more path. It now prefers _savedOrderNames, the canonical saved list that saveOrder keeps merged with hidden apps at their ranks, over the possibly pre-drag kv snapshot the stashed load fetched. - The post-uninstall optimistic render now also skips the load fade; it was the one in-place rebuild still hiding the grid behind the opacity-0 icon gate. - mergeSavedOrder's rank rescan collapsed to a single forward insertion pointer (verified output-identical; the 20 unit tests pin the behavior).
This commit is contained in:
@@ -183,7 +183,7 @@ function showUninstallModal ({ appName, appTitle, appUid, removesTile, self, $el
|
||||
// and restores its position if it comes back.
|
||||
if ( removesTile ) {
|
||||
self._apps = self._apps.filter(a => a.name !== appName);
|
||||
self.renderApps($el_window, { preservePage: true });
|
||||
self.renderApps($el_window, { preservePage: true, instant: true });
|
||||
}
|
||||
// Keep the user's page and skip the load fade — this is a
|
||||
// background sync, not a fresh visit.
|
||||
@@ -925,11 +925,17 @@ const TabApps = {
|
||||
this._pendingLoad = null;
|
||||
if ( pending.loadSeq < (this._appliedSeq || 0) ) return;
|
||||
this._appliedSeq = pending.loadSeq;
|
||||
this._savedOrderNames = pending.orderedNames;
|
||||
|
||||
const orderedNames = this._hasCustomOrder && Array.isArray(this._apps)
|
||||
? serializeAppOrder(this._apps)
|
||||
// The drag that deferred this load may have just saved a newer order;
|
||||
// _savedOrderNames tracks the canonical saved list (saveOrder keeps
|
||||
// it merged, with hidden apps at their ranks). Prefer it over the kv
|
||||
// snapshot the stashed load fetched — that may predate the drag — and
|
||||
// never reconcile against the visible-only on-screen order, which
|
||||
// would tail-append any app returning to the grid.
|
||||
const orderedNames = this._hasCustomOrder && Array.isArray(this._savedOrderNames)
|
||||
? this._savedOrderNames
|
||||
: pending.orderedNames;
|
||||
this._savedOrderNames = orderedNames;
|
||||
this._hasCustomOrder = Array.isArray(orderedNames) && orderedNames.length > 0;
|
||||
this._apps = reconcileAppOrder(pending.merged, orderedNames);
|
||||
this.renderApps(pending.$el_window, { preservePage: true, instant: true });
|
||||
|
||||
@@ -94,35 +94,26 @@ export function mergeSavedOrder (currentNames, previousNames) {
|
||||
const currentSet = new Set(result);
|
||||
const prevSet = new Set(previousNames);
|
||||
// A survivor is a name present in both lists; re-inserted missing names
|
||||
// and brand-new names never count when locating the k-th survivor.
|
||||
// and brand-new names never count when advancing past a survivor.
|
||||
const isSurvivor = name => currentSet.has(name) && prevSet.has(name);
|
||||
|
||||
const seen = new Set();
|
||||
let rank = 0; // survivors encountered so far in the saved order
|
||||
let lastInsert = -1; // keeps runs of missing names in their saved order
|
||||
// Single forward pointer over `result`: for each survivor in the saved
|
||||
// order it advances just past the next survivor; each missing name is
|
||||
// spliced in at the pointer, which puts it right after the same number
|
||||
// of survivors that preceded it in the saved order — its rank.
|
||||
let at = 0;
|
||||
for ( const name of previousNames ) {
|
||||
if ( typeof name !== 'string' || name.length === 0 ) continue;
|
||||
if ( seen.has(name) ) continue;
|
||||
seen.add(name);
|
||||
if ( currentSet.has(name) ) {
|
||||
rank++;
|
||||
lastInsert = -1;
|
||||
while ( at < result.length && ! isSurvivor(result[at]) ) at++;
|
||||
at++;
|
||||
continue;
|
||||
}
|
||||
// Find the index just past the rank-th survivor in the result.
|
||||
let at = 0;
|
||||
if ( rank > 0 ) {
|
||||
let survivors = 0;
|
||||
for ( let i = 0; i < result.length; i++ ) {
|
||||
if ( isSurvivor(result[i]) && ++survivors === rank ) {
|
||||
at = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( lastInsert >= at ) at = lastInsert + 1;
|
||||
result.splice(at, 0, name);
|
||||
lastInsert = at;
|
||||
at++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user