← back to Approvals Viewer
approvals-viewer UI: always show action buttons + fetch error/retry so it never hangs on Loading
f3b563d47b6bc8d98f49bd68e9b9d201face3536 · 2026-08-11 12:59:54 -0700 · Steve Abrams
Files touched
Diff
commit f3b563d47b6bc8d98f49bd68e9b9d201face3536
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 11 12:59:54 2026 -0700
approvals-viewer UI: always show action buttons + fetch error/retry so it never hangs on Loading
---
public/index.html | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/public/index.html b/public/index.html
index 2199886..e684c7e 100644
--- a/public/index.html
+++ b/public/index.html
@@ -33,7 +33,7 @@ button{border:0;border-radius:12px;padding:14px 22px;font-size:16px;font-weight:
<span class=tally id=tally></span>
</header>
<main id=main><div class=card><div class=body>Loading…</div></div></main>
-<div class=actions id=actions style=display:none>
+<div class=actions id=actions style=display:flex>
<button class=b-undo id=undo title="Undo last (U)">↶ Undo</button>
<button class=b-no onclick="decide('reject')">❌ Reject <span class=kbd>←</span></button>
<button class=b-sk onclick="decide('defer')">⏭ Defer <span class=kbd>↓</span></button>
@@ -72,7 +72,7 @@ function render(){
m.querySelector('.body').scrollTop=0;
}
async function decide(decision){
- const x=memos[i];tally[decision]++;lastAction={file:x.file,decision,idx:i};
+ const x=memos[i];if(!x)return;tally[decision]++;lastAction={file:x.file,decision,idx:i};
if(decision!=='defer'){try{await fetch('/api/decide',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({file:x.file,decision})});}catch(e){}}
i++;render();
}
@@ -89,5 +89,9 @@ addEventListener('keydown',e=>{
else if(e.key==='ArrowDown'||e.key===' '||e.key==='s'){e.preventDefault();decide('defer');}
else if(e.key==='u')undo();
});
-fetch('/api/memos').then(r=>r.json()).then(d=>{memos=d;total=d.length;render();});
+function load(){fetch('/api/memos').then(r=>{if(!r.ok)throw new Error('HTTP '+r.status);return r.json();})
+ .then(d=>{memos=d;total=d.length;i=0;render();})
+ .catch(e=>{document.getElementById('actions').style.display='none';
+ document.getElementById('main').innerHTML='<div class=done><h2>⚠️ Could not load memos</h2><p style=color:#8a8f9a>'+e.message+'</p><p><button onclick="load()">↻ Retry</button></p></div>';});}
+load();
</script></body></html>
← 06062c8 approvals-viewer: re-enable Basic auth + pin default port 97
·
back to Approvals Viewer
·
chore: harden /api/undo (path-traversal guard + decision whi a188fef →