update dashboard

This commit is contained in:
Thomas Ciesla
2026-01-08 08:57:31 +01:00
parent 7078055dc8
commit dfedbe8be5

View File

@@ -1456,12 +1456,13 @@ def get_dashboard_html() -> str:
.btn-header { background: transparent; border: 1px solid var(--border); color: var(--text-secondary); padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px; text-decoration: none; }
.btn-header:hover { border-color: var(--accent); color: var(--accent); }
main { padding: 24px; max-width: 1800px; margin: 0 auto; }
.stats-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 16px; margin-bottom: 24px; }
.stats-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 16px; margin-bottom: 24px; }
.stat-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; }
.stat-label { font-size: 12px; color: var(--text-secondary); margin-bottom: 8px; text-transform: uppercase; }
.stat-value { font-size: 28px; font-weight: 700; }
.stat-value.success { color: var(--success); }
.stat-value.warning { color: var(--warning); }
.stat-value.danger { color: var(--danger); }
.stat-value.link11 { color: var(--link11); }
.stat-value.direct { color: var(--danger); }
.top-shops-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 24px; }
@@ -1584,9 +1585,10 @@ def get_dashboard_html() -> str:
<main>
<div class="stats-grid">
<div class="stat-card"><div class="stat-label">Server Online</div><div class="stat-value success" id="statAgents">0</div></div>
<div class="stat-card"><div class="stat-label">Shops Aktiv</div><div class="stat-value" id="statShops">0</div></div>
<div class="stat-card"><div class="stat-label">Shops Aktiv</div><div class="stat-value" id="statShops">0/0</div></div>
<div class="stat-card"><div class="stat-label">🛡️ Link11</div><div class="stat-value link11" id="statLink11">0</div></div>
<div class="stat-card"><div class="stat-label">⚡ Direkt</div><div class="stat-value direct" id="statDirect">0</div></div>
<div class="stat-card"><div class="stat-label">🚫 Bans</div><div class="stat-value danger" id="statBans">0</div></div>
<div class="stat-card"><div class="stat-label">Human/min</div><div class="stat-value success" id="statHumanRpm">0</div></div>
<div class="stat-card"><div class="stat-label">Bot/min</div><div class="stat-value warning" id="statBotRpm">0</div></div>
</div>
@@ -1677,8 +1679,8 @@ def get_dashboard_html() -> str:
function renderShops(){const all=Object.values(shops);let l11=all.filter(s=>s.link11),dir=all.filter(s=>!s.link11);l11=getSortedShops(l11,'link11');dir=getSortedShops(dir,'direct');document.getElementById('link11Count').textContent=l11.length+' Shops';document.getElementById('directCount').textContent=dir.length+' Shops';document.getElementById('shopsLink11Table').innerHTML=renderShopRows(l11);document.getElementById('shopsDirectTable').innerHTML=renderShopRows(dir);}
function renderShopRows(l){return l.map(s=>{const modeStr=s.monitor_only?'🔍 Monitor':((s.bot_mode?'🤖':'')+(s.country_mode?' 🌍':''))||'-';const bansStr=s.monitor_only?'-':((s.stats?.active_bot_bans||0)+(s.stats?.active_country_bans||0));return '<tr><td><span class="status-badge status-'+(s.status||'inactive')+'">'+(s.status==='active'?'':'')+'</span></td><td><span class="domain-link" onclick="openDetailModal(\\''+s.domain+'\\')">'+s.domain+'</span></td><td>'+(s.agent_hostname||'-')+'</td><td>'+modeStr+'</td><td>'+((s.stats?.req_per_min||0).toFixed(1))+'</td><td>'+bansStr+'</td><td>'+formatRuntime(s.runtime_minutes)+'</td><td class="actions"><a href="https://'+s.domain+'" target="_blank" class="btn-icon">🔗</a>'+(s.status==='active'?'<button class="btn-icon" onclick="openLogs(\\''+s.domain+'\\')">📜</button><button class="btn btn-danger" onclick="deactivateShop(\\''+s.domain+'\\')">Stop</button>':'<button class="btn btn-primary" onclick="openActivateModal(\\''+s.domain+'\\')">Start</button>')+'</td></tr>';}).join('');}
function renderTopShops(){const l=Object.values(shops).filter(s=>s.status==='active').sort((a,b)=>(b.stats?.req_per_min||0)-(a.stats?.req_per_min||0)).slice(0,10);document.getElementById('topShopsList').innerHTML=l.map(s=>{const bans=(s.stats?.active_bot_bans||0)+(s.stats?.active_country_bans||0);return '<div class="top-shop-item" onclick="openDetailModal(\\''+s.domain+'\\')"><div class="top-shop-domain">'+s.domain+'</div><div class="top-shop-stats"><span class="top-shop-req">'+((s.stats?.req_per_min||0).toFixed(1))+' req/m</span><span class="top-shop-bans">'+bans+' bans</span></div></div>';}).join('')||'<div style="color:var(--text-secondary)">Keine aktiven Shops</div>';}
function updateStats(s){document.getElementById('statAgents').textContent=s.agents_online||0;document.getElementById('statShops').textContent=s.shops_active||0;document.getElementById('statLink11').textContent=s.shops_link11||0;document.getElementById('statDirect').textContent=s.shops_direct||0;document.getElementById('statHumanRpm').textContent=(s.human_rpm||0).toFixed(1);document.getElementById('statBotRpm').textContent=(s.bot_rpm||0).toFixed(1);}
function refreshStats(){const l=Object.values(shops),a=l.filter(s=>s.status==='active');document.getElementById('statShops').textContent=a.length;document.getElementById('statLink11').textContent=l.filter(s=>s.link11).length;document.getElementById('statDirect').textContent=l.filter(s=>!s.link11).length;document.getElementById('statHumanRpm').textContent=a.reduce((sum,s)=>sum+(s.stats?.human_rpm||0),0).toFixed(1);document.getElementById('statBotRpm').textContent=a.reduce((sum,s)=>sum+(s.stats?.bot_rpm||0),0).toFixed(1);}
function updateStats(s){document.getElementById('statAgents').textContent=s.agents_online||0;document.getElementById('statShops').textContent=(s.shops_active||0)+'/'+(s.shops_total||0);document.getElementById('statLink11').textContent=s.shops_link11||0;document.getElementById('statDirect').textContent=s.shops_direct||0;document.getElementById('statBans').textContent=s.active_bans||0;document.getElementById('statHumanRpm').textContent=(s.human_rpm||0).toFixed(1);document.getElementById('statBotRpm').textContent=(s.bot_rpm||0).toFixed(1);}
function refreshStats(){const l=Object.values(shops),a=l.filter(s=>s.status==='active');document.getElementById('statShops').textContent=a.length+'/'+l.length;document.getElementById('statLink11').textContent=l.filter(s=>s.link11).length;document.getElementById('statDirect').textContent=l.filter(s=>!s.link11).length;document.getElementById('statBans').textContent=l.reduce((sum,s)=>sum+(s.stats?.active_bot_bans||0)+(s.stats?.active_country_bans||0),0);document.getElementById('statHumanRpm').textContent=a.reduce((sum,s)=>sum+(s.stats?.human_rpm||0),0).toFixed(1);document.getElementById('statBotRpm').textContent=a.reduce((sum,s)=>sum+(s.stats?.bot_rpm||0),0).toFixed(1);}
async function approveAgent(id){await fetch('/api/agents/'+id+'/approve',{method:'POST'});}
function openActivateModal(d){document.getElementById('activateDomain').value=d;document.getElementById('activateDomainDisplay').value=d;document.getElementById('monitorOnlyCheck').checked=false;document.getElementById('botModeCheck').checked=true;document.getElementById('countryModeCheck').checked=false;toggleMonitorOnly();toggleBotOptions();toggleCountryOptions();document.getElementById('activateModal').classList.add('open');}
function closeModal(id){document.getElementById(id).classList.remove('open');}