🔒 Repository is read-only – file editing is disabled.

PaganLinux/pagan-web-v2/templates/admin/logs.html main

102 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
{% extends "admin/layout.html" %}
{% block admin_title %}Logi{% endblock %}
{% block admin_h1 %} Logi{% endblock %}
{% block admin_sub %}Logi buildów i systemowe{% endblock %}
{% block admin_head %}
<style>
.log-tabs { display:flex; gap:0.4rem; margin-bottom:0.8rem; flex-wrap:wrap; }
.log-tab { padding:0.35rem 0.9rem; border-radius:var(--radius-sm); background:#0d1117; border:1px solid var(--border);
 color:var(--muted); cursor:pointer; font-size:0.82rem; }
.log-tab.active { background:var(--accent); color:#000; font-weight:600; }
.log-list { max-height:60vh; overflow:auto; border:1px solid var(--border); border-radius:var(--radius);
 background:#0d1117; }
.log-file { display:flex; justify-content:space-between; gap:0.5rem; padding:0.45rem 0.7rem;
 border-bottom:1px solid #111; cursor:pointer; font-size:0.8rem; }
.log-file:hover { background:#161b22; }
.log-file.nm { font-family:'JetBrains Mono',monospace; }
.log-file.meta { color:var(--muted); white-space:nowrap; }
.log-view { white-space:pre-wrap; font-family:'JetBrains Mono',monospace; font-size:0.74rem; line-height:1.5;
 background:#0a0a0a; border:1px solid #1a1a2e; border-radius:var(--radius-sm); padding:0.8rem;
 max-height:60vh; overflow:auto; display:none; }
</style>
{% endblock %}
{% block admin_content %}
<div class="log-tabs">
 <div class="log-tab active" id="tab-build" onclick="switchSrc('build')">Buildy</div>
 <div class="log-tab" id="tab-sys" onclick="switchSrc('sys')">Systemowe</div>
 <select id="log-tail" style="margin-left:auto" onchange="loadList()">
 <option value="100">100 linii</option>
 <option value="200" selected>200 linii</option>
 <option value="500">500 linii</option>
 <option value="2000">2000 linii</option>
 </select>
 <button class="log-tab" onclick="downloadLog()" title="Pobierz wybrany log (albo najnowszy)">Pobierz</button>
 <button class="log-tab" style="color:var(--red)" onclick="clearLogs()" title="Wyczyść wybrany log; w zakładce Buildy – wszystkie">Wyczyść</button>
</div>
<div class="log-list" id="log-list"></div>
<div class="log-view" id="log-view"></div>
<script>
let SRC='build';
let CURRENT=null;
async function switchSrc(s){
 SRC=s;
 document.getElementById('tab-build').classList.toggle('active', s==='build');
 document.getElementById('tab-sys').classList.toggle('active', s==='sys');
 document.getElementById('log-view').style.display='none';
 loadList();
}
async function loadList(){
 const el=document.getElementById('log-list');
 try{
 const r=await fetch('/admin/logs/api?src='+SRC); const d=await r.json();
 let html='';
 d.files.forEach(f=>{
 html+=`<div class="log-file" onclick="viewLog('${f.name}')">
 <span class="nm">${f.name}</span><span class="meta">${f.size} · ${f.mtime}</span></div>`;
 });
 el.innerHTML=html||'<div class="log-file">brak logów</div>';
 }catch(e){ el.innerHTML='<div class="log-file">błąd</div>'; }
}
async function viewLog(name){
 CURRENT=name;
 const tail=document.getElementById('log-tail').value;
 const view=document.getElementById('log-view');
 try{
 const r=await fetch(`/admin/logs/view?src=${SRC}&name=${encodeURIComponent(name)}&tail=${tail}`);
 const d=await r.json();
 view.style.display='block'; view.textContent = d.ok? d.content: ('błąd: '+(d.error||'?'));
 document.getElementById('log-list').style.display='none';
 }catch(e){ view.style.display='block'; view.textContent='błąd: '+e; }
}
function csrfToken(){
 const m=document.querySelector('meta[name="csrf-token"]');
 return m? m.getAttribute('content') : '';
}
function downloadLog(){
 const q='src='+SRC+(CURRENT? '&name='+encodeURIComponent(CURRENT): '');
 window.location='/admin/logs/download?'+q;
}
async function clearLogs(){
 const scope = CURRENT ? ('plik „'+CURRENT+'”') : (SRC==='build' ? 'WSZYSTKIE logi buildów' : null);
 if(!scope){ alert('Logi systemowe: najpierw kliknij konkretny plik, który chcesz wyczyścić.'); return; }
 if(!confirm('Wyczyścić '+scope+'? Pliki zostaną OPRÓŻNIONE (nie usunięte).')) return;
 try{
 const fd=new URLSearchParams();
 if(CURRENT) fd.append('name', CURRENT);
 const r=await fetch('/admin/logs/clear?src='+SRC,{method:'POST',
 headers:{'X-CSRF-Token': csrfToken(),'Content-Type':'application/x-www-form-urlencoded'},
 body:fd.toString()});
 const d=await r.json();
 if(d.ok){ CURRENT=null; document.getElementById('log-view').style.display='none';
 document.getElementById('log-list').style.display=''; loadList(); }
 else alert(d.error||'błąd czyszczenia');
 }catch(e){ alert('Błąd: '+e); }
}
// przycisk "wróć" po podglądzie
document.getElementById('log-view').addEventListener('dblclick', ()=>{
 document.getElementById('log-view').style.display='none';
 document.getElementById('log-list').style.display='';
});
loadList();
</script>
{% endblock %}