fix: admin dashboard format errors — use JS for stats, string concat for SMTP values, fix layout overlap
This commit is contained in:
parent
99e47fcb17
commit
0f5c584c50
|
|
@ -330,6 +330,7 @@ func (s *Server) routes() *http.ServeMux {
|
|||
mux.HandleFunc("/logout", s.handleUserWebLogout)
|
||||
mux.HandleFunc("/admin/login", s.handleAdminLogin)
|
||||
mux.HandleFunc("/admin/dashboard", s.handleAdminDashboard)
|
||||
mux.HandleFunc("/admin/api/stats", s.handleAdminStats)
|
||||
mux.HandleFunc("/admin/", s.handleAdminAPI)
|
||||
mux.HandleFunc("/", s.handleNotFound)
|
||||
return mux
|
||||
|
|
@ -1336,8 +1337,8 @@ a{color:#6366f1}
|
|||
h1{border-bottom:1px solid #2a2a3c;padding-bottom:12px}
|
||||
h2{margin-top:24px;font-size:16px}
|
||||
.stat{background:#1a1a28;border:1px solid #2a2a3c;padding:12px 16px;border-radius:8px;margin:8px 0}
|
||||
.row{display:flex;gap:16px;flex-wrap:wrap}
|
||||
.col{flex:1;min-width:300px}
|
||||
.row{display:flex;gap:20px;flex-wrap:wrap;margin-top:8px}
|
||||
.col{flex:1;min-width:280px;max-width:50%}
|
||||
table{width:100%;border-collapse:collapse;margin-top:8px}
|
||||
th,td{text-align:left;padding:8px 12px;border-bottom:1px solid #2a2a3c}
|
||||
th{font-size:12px;color:#888;text-transform:uppercase}
|
||||
|
|
@ -1360,8 +1361,8 @@ form{margin-top:8px}
|
|||
</head><body>
|
||||
<h1>Verstak Sync Server</h1>
|
||||
<div class="row">
|
||||
<div class="stat"><strong>Устройств:</strong> %d</div>
|
||||
<div class="stat"><strong>Операций:</strong> %d</div>
|
||||
<div class="stat"><strong>Устройств:</strong> <span id="dev-count">0</span></div>
|
||||
<div class="stat"><strong>Операций:</strong> <span id="op-count">0</span></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
|
@ -1376,6 +1377,10 @@ fetch('/admin/api/keys').then(r=>r.json()).then(keys=>{
|
|||
keys.map(k=>'<tr><td>'+k.name+'</td><td class="key-cell" title="'+k.api_key+'">'+k.api_key+'</td>'+
|
||||
'<td><button class="btn copy-btn" onclick="copyKey(\''+k.api_key+'\',this)">Копировать</button></td>'+
|
||||
'<td><button class="btn btn-danger" onclick="delKey(\''+k.id+'\')">Удалить</button></td></tr>').join('')+'</table>'
|
||||
document.getElementById('dev-count').textContent=keys.length
|
||||
})
|
||||
fetch('/admin/api/stats').then(r=>r.json()).then(stats=>{
|
||||
document.getElementById('op-count').textContent=stats.ops||'0'
|
||||
})
|
||||
function copyKey(key,btn){
|
||||
navigator.clipboard.writeText(key).then(()=>{
|
||||
|
|
@ -1396,12 +1401,12 @@ function delKey(id){if(confirm('Удалить ключ?'))fetch('/admin/api/key
|
|||
<h2>SMTP (для писем)</h2>
|
||||
<div class="section">
|
||||
<form action="/admin/api/smtp" method="POST">
|
||||
<div class="form-row"><label>Сервер</label><input name="smtp_host" value="%s" placeholder="smtp.example.com"></div>
|
||||
<div class="form-row"><label>Порт</label><input name="smtp_port" value="%s" placeholder="587"></div>
|
||||
<div class="form-row"><label>Логин</label><input name="smtp_user" value="%s" placeholder="user@example.com"></div>
|
||||
<div class="form-row"><label>Сервер</label><input name="smtp_host" value="` + smtpHost + `" placeholder="smtp.example.com"></div>
|
||||
<div class="form-row"><label>Порт</label><input name="smtp_port" value="` + smtpPort + `" placeholder="587"></div>
|
||||
<div class="form-row"><label>Логин</label><input name="smtp_user" value="` + smtpUser + `" placeholder="user@example.com"></div>
|
||||
<div class="form-row"><label>Пароль</label><input type="password" name="smtp_pass" placeholder="••••••••"></div>
|
||||
<div class="form-row"><label>От кого</label><input name="smtp_from" value="%s" placeholder="noreply@example.com"></div>
|
||||
<div class="form-row"><label>URL сервера</label><input name="server_url" value="%s" placeholder="https://example.com:47732"></div>
|
||||
<div class="form-row"><label>От кого</label><input name="smtp_from" value="` + smtpFrom + `" placeholder="noreply@example.com"></div>
|
||||
<div class="form-row"><label>URL сервера</label><input name="server_url" value="` + srvURL + `" placeholder="https://example.com:47732"></div>
|
||||
<div style="margin-top:8px"><button class="btn btn-primary">Сохранить SMTP</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -1409,10 +1414,19 @@ function delKey(id){if(confirm('Удалить ключ?'))fetch('/admin/api/key
|
|||
</div>
|
||||
|
||||
<p style="margin-top:16px"><a href="/api/v1/health">Health check</a></p>
|
||||
</body></html>`, deviceCount, opsCount, smtpHost, smtpPort, smtpUser, smtpFrom, srvURL)
|
||||
</body></html>`)
|
||||
w.Write([]byte(html))
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminStats(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.requireAdmin(w, r) {
|
||||
return
|
||||
}
|
||||
var opsCount int
|
||||
s.db.QueryRow("SELECT COUNT(*) FROM server_ops").Scan(&opsCount)
|
||||
jsonOK(w, map[string]int{"ops": opsCount})
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminAPI(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.requireAdmin(w, r) {
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue