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:
parent
f78dc43374
commit
118cb921f0
1 changed files with 27 additions and 6 deletions
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue