4fb4e77007
- New GET /api/user/hosts (auth-only): all hosts for admins, group-filtered list for everyone else. - accessibleHosts() accepts a pre-resolved user.groups, so the web UI's OIDC session skips a redundant LDAP getGroups(dn) call. - Dashboard shows a "Hosts you can reach" / "All hosts" table. - @simpleworkjs/ldap 1.0.1 fixes addSshKey's ObjectClassViolationError on accounts predating the ldapPublicKey objectClass -- was aborting key injection (and the SSH connection) on affected accounts. - Bump to 1.5.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
90 lines
3.3 KiB
Plaintext
90 lines
3.3 KiB
Plaintext
<%- include('top') %>
|
||
<script type="text/javascript">app.auth.forceLogin();</script>
|
||
|
||
<div class="row g-3 mb-4">
|
||
<div class="col-6 col-md-3">
|
||
<div class="card shadow-sm text-center"><div class="card-body">
|
||
<div class="display-6" id="stat-active">–</div>
|
||
<div class="text-muted small text-uppercase">Active sessions</div>
|
||
</div></div>
|
||
</div>
|
||
<div class="col-6 col-md-3">
|
||
<div class="card shadow-sm text-center"><div class="card-body">
|
||
<div class="display-6" id="stat-total">–</div>
|
||
<div class="text-muted small text-uppercase">Total connections</div>
|
||
</div></div>
|
||
</div>
|
||
<div class="col-6 col-md-3">
|
||
<div class="card shadow-sm text-center"><div class="card-body">
|
||
<div class="display-6 text-danger" id="stat-fail">–</div>
|
||
<div class="text-muted small text-uppercase">Failed</div>
|
||
</div></div>
|
||
</div>
|
||
<div class="col-6 col-md-3">
|
||
<div class="card shadow-sm text-center"><div class="card-body">
|
||
<div class="display-6" id="stat-users">–</div>
|
||
<div class="text-muted small text-uppercase">Users seen</div>
|
||
</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row g-3 mb-4">
|
||
<div class="col-12">
|
||
<div class="card shadow-sm">
|
||
<div class="card-header"><i class="fa-solid fa-network-wired me-1"></i> <span id="my-hosts-title">Hosts you can reach</span></div>
|
||
<table class="table table-sm mb-0"><tbody id="my-hosts"></tbody></table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row g-3">
|
||
<div class="col-md-6">
|
||
<div class="card shadow-sm"><div class="card-header"><i class="fa-solid fa-server me-1"></i> Top hosts</div>
|
||
<table class="table table-sm mb-0"><tbody id="top-hosts"></tbody></table>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="card shadow-sm"><div class="card-header"><i class="fa-solid fa-user me-1"></i> Top users</div>
|
||
<table class="table table-sm mb-0"><tbody id="top-users"></tbody></table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
function rows(sel, list){
|
||
var $b = $(sel).empty();
|
||
if(!list || !list.length){ $b.append('<tr><td class="text-muted">No data.</td></tr>'); return; }
|
||
list.forEach(function(x){
|
||
$b.append('<tr><td>' + app.jump.esc(x.name) + '</td><td class="text-end">' + x.count + '</td></tr>');
|
||
});
|
||
}
|
||
function hostRows(sel, hosts){
|
||
var $b = $(sel).empty();
|
||
if(!hosts || !hosts.length){ $b.append('<tr><td class="text-muted">No hosts reachable.</td></tr>'); return; }
|
||
hosts.forEach(function(h){
|
||
var addr = (h.metadata && (h.metadata.ip || h.metadata.address)) || '';
|
||
$b.append('<tr><td>' + app.jump.esc(h.displayName || h.name || h.slug) + '</td>'
|
||
+ '<td class="text-muted small">' + app.jump.esc(h.slug) + '</td>'
|
||
+ '<td class="text-end text-muted small">' + app.jump.esc(addr) + '</td></tr>');
|
||
});
|
||
}
|
||
$(document).ready(async function(){
|
||
app.jump.metrics(function(error, data){
|
||
if(error || !data) return;
|
||
$('#stat-active').text(data.active);
|
||
$('#stat-total').text(data.total);
|
||
$('#stat-fail').text(data.fail);
|
||
$('#stat-users').text((data.topUsers || []).length);
|
||
rows('#top-hosts', data.topHosts);
|
||
rows('#top-users', data.topUsers);
|
||
});
|
||
await app.auth.loadUser();
|
||
if(app.auth.isAdmin()) $('#my-hosts-title').text('All hosts');
|
||
app.jump.hosts(function(error, data){
|
||
if(error) return hostRows('#my-hosts', []);
|
||
hostRows('#my-hosts', data && data.results);
|
||
});
|
||
});
|
||
</script>
|
||
<%- include('bottom') %>
|