Clear stale Framey store listings during refresh

This commit is contained in:
SAPHID committed 2026-10-25 23:09:14 +00:00
1 parent 1701e622dc
commit 3f4aaf539c
2 files changed
+32 -4

No files matched your search

+23
View File
@@ -60,6 +60,7 @@ assert.equal(el('deckyJobStatus').textContent,'Installed Plugin 2');
assert.equal(el('deckyJobProgress').value,100);
assert.equal(el('deckyJobCheck').hidden,true);
assert.equal(session.has('frameyPluginJob'),false);
// A stopped Decky service must still offer recovery by removing its owned plugin.
ctx.mockApi=async path => path==='/api/decky' ?
{managed:true,running:false,plugins:[{storeId:2,name:'Plugin 2',version:'1.0'}]} :
@@ -81,6 +82,28 @@ await vm.runInContext('deckyChange("update",{id:2,name:"Plugin 2",sha256:"b".rep
assert.match(el('deckyJobStatus').textContent,/Error: archive digest mismatch/);
assert.equal(session.has('frameyPluginJob'),false);
// A failed refresh must remove old install buttons. A late older response
// must not replace the newer catalog the wearer just requested.
ctx.mockApi=async path => {assert.equal(path,'/api/decky/store');throw Error('offline');};
vm.runInContext('api=mockApi',ctx);
await vm.runInContext('loadDeckyStore()',ctx);
assert.match(el('deckyStoreSummary').textContent,/Store unavailable: offline/);
assert.equal(el('deckyStoreList').children.length,0);
let finishOld, finishNew;
ctx.mockApi=path => {assert.equal(path,'/api/decky/store');
return new Promise(resolve=>{if(!finishOld)finishOld=resolve;else finishNew=resolve;});};
vm.runInContext('api=mockApi',ctx);
const old=vm.runInContext('loadDeckyStore()',ctx);
const current=vm.runInContext('loadDeckyStore()',ctx);
assert.equal(el('deckyStoreList').children.length,0);
assert.equal(el('deckyStoreSummary').textContent,'Loading official Decky store…');
finishNew({plugins:[{id:98,name:'Current',version:'2.0',description:'Latest'}]});
await current;
finishOld({plugins:[{id:97,name:'Stale',version:'1.0',description:'Older'}]});
await old;
assert.match(el('deckyStoreList').children[0].children[0].textContent,/Current/);
assert.doesNotMatch(el('deckyStoreList').children[0].children[0].textContent,/Stale/);
// A saved job does not survive a server restart. Clear it instead of offering
// Check result forever for an ID that the new server cannot know.
session.set('frameyPluginJob',JSON.stringify({job:'old-job',action:'install',name:'Plugin 2'}));
+9 -4
View File
@@ -103,7 +103,8 @@ async function refreshGames(){const list=byId('games');try{const data=await api(
catch(error){byId('actionStatus').textContent=error.message;quit.disabled=false;}};
row.append(name,quit);list.append(row);}if(!data.running.length)list.textContent='No games are running.';
}catch(error){list.textContent=error.message;}}
let deckyState=null, deckyStore=[], deckyStoreIndex=0, activeFrameyId=null, frameySession=null, deckyBusy=false;
let deckyState=null, deckyStore=[], deckyStoreIndex=0, deckyStoreRequest=0,
activeFrameyId=null, frameySession=null, deckyBusy=false;
async function refreshDecky(){try{deckyState=await api('/api/decky');
byId('deckyState').textContent=deckyState.running?'Decky loader is running. Backend loading is not a VR menu check.':
deckyState.managed?'Decky is stopped. You can remove a managed plugin to recover, then start Decky from Frame Control on your computer.':
@@ -117,10 +118,14 @@ async function refreshDecky(){try{deckyState=await api('/api/decky');
button.disabled=deckyBusy;button.onclick=()=>deckyChange('remove',{id:plugin.storeId,name:plugin.name});row.append(button);}
list.append(row);}if(!deckyState.plugins?.length)list.textContent='No managed plugins installed.';
showDeckyStore();}catch(error){byId('deckyState').textContent=error.message;}}
async function loadDeckyStore(){byId('deckyStorePanel').hidden=false;
async function loadDeckyStore(){const request=++deckyStoreRequest;byId('deckyStorePanel').hidden=false;
deckyStore=[];deckyStoreIndex=0;showDeckyStore();
byId('deckyStoreSummary').textContent='Loading official Decky store…';
try{const data=await api('/api/decky/store');deckyStore=data.plugins;deckyStoreIndex=0;showDeckyStore();}
catch(error){byId('deckyStoreSummary').textContent=`Store unavailable: ${error.message}`;}}
try{const data=await api('/api/decky/store');if(request!==deckyStoreRequest)return;
deckyStore=data.plugins;deckyStoreIndex=0;showDeckyStore();}
catch(error){if(request!==deckyStoreRequest)return;
deckyStore=[];deckyStoreIndex=0;showDeckyStore();
byId('deckyStoreSummary').textContent=`Store unavailable: ${error.message}`;}}
function showDeckyStore(){const list=byId('deckyStoreList');list.replaceChildren();
const q=byId('deckySearch').value.trim().toLowerCase();
const filter=byId('deckyStoreFilter').value;