feat(webui): add summarize loading indicator, wrap long lines, auto-load last 25 on first channel, optional auto-follow (poll every 3s)

This commit is contained in:
Thomas Cravey 2025-08-16 15:45:27 -05:00
parent f78dc43374
commit 118cb921f0

View file

@ -217,7 +217,7 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@2/css/pico.min.css">
<style>
body { padding: 1rem; }
pre { max-height: 50vh; overflow: auto; }
pre { max-height: 50vh; overflow: auto; white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 768px) {
.grid { grid-template-columns: 1fr !important; }
@ -225,7 +225,7 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
}
</style>
<script>
const st={token: localStorage.getItem('token')||''};
const st={token: localStorage.getItem('token')||'', tailTimer:null, tailLoading:false};
function setToken(v){ st.token=v; localStorage.setItem('token', v); }
async function api(path, params){
const url = new URL(path, window.location.origin);
@ -248,26 +248,43 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
async function loadChannels(){
try{ const data = await api('/api/channels');
const sel = document.getElementById('channel'); sel.innerHTML = '';
data.forEach(c=>{ const o=document.createElement('option'); o.value=c; o.textContent=c; sel.appendChild(o); });
data.forEach(function(c){ const o=document.createElement('option'); o.value=c; o.textContent=c; sel.appendChild(o); });
// Auto-tail default channel (first) with 25 lines
if(data.length>0){ document.getElementById('limit').value = '25'; doTail(); }
}catch(e){ console.error(e); }
}
async function doTail(){
if(st.tailLoading) return; st.tailLoading=true;
const ch = document.getElementById('channel').value;
const lim = document.getElementById('limit').value || '100';
try{ const data = await api('/api/tail',{query:{channel:ch,limit:lim}});
const out = data.map(m => (m.time + ' ' + m.author + ': ' + m.body)).join('\n');
document.getElementById('tail').textContent = out;
}catch(e){ document.getElementById('tail').textContent = 'error: '+e; }
st.tailLoading=false;
}
async function doSumm(){
const ch = document.getElementById('channel').value;
const win = document.getElementById('window').value || '6h';
const push = document.getElementById('push').checked ? '1' : '0';
const btn = document.getElementById('summBtn');
const prog = document.getElementById('summProg');
btn.disabled = true; prog.style.display = 'inline-block';
try{ const data = await api('/api/trigger',{query:{channel:ch,window:win,push:push}});
document.getElementById('summary').textContent = data.summary || '(empty)';
}catch(e){ document.getElementById('summary').textContent = 'error: '+e; }
btn.disabled = false; prog.style.display = 'none';
}
window.addEventListener('DOMContentLoaded', ()=>{ loadInfo(); loadChannels(); });
function onFollowToggle(cb){
if(cb.checked){
if(st.tailTimer) clearInterval(st.tailTimer);
st.tailTimer = setInterval(doTail, 3000);
}else{
if(st.tailTimer) { clearInterval(st.tailTimer); st.tailTimer=null; }
}
}
function onChannelChange(){ doTail(); }
</script>
</head>
<body>
@ -276,8 +293,9 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
<article>
<div class="grid">
<label>Auth token<input type="password" id="tok" placeholder="HTTP_TOKEN" oninput="setToken(this.value)"/></label>
<label>Channel<select id="channel"></select></label>
<label>Limit<input type="number" id="limit" value="100"/></label>
<label>Channel<select id="channel" onchange="onChannelChange()"></select></label>
<label>Limit<input type="number" id="limit" value="25"/></label>
<label><input type="checkbox" id="follow" onchange="onFollowToggle(this)"/> Follow</label>
<button onclick="doTail()">Refresh tail</button>
</div>
<pre id="tail"></pre>
@ -286,7 +304,10 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
<div class="grid">
<label>Window<input type="text" id="window" value="6h"/></label>
<label><input type="checkbox" id="push"/> Send via Pushover</label>
<button onclick="doSumm()">Summarize</button>
<div>
<button id="summBtn" onclick="doSumm()">Summarize</button>
<progress id="summProg" value="0" max="1" style="display:none; vertical-align: middle;"></progress>
</div>
</div>
<pre id="summary"></pre>
</article>