Files
Maintainarr/internal/views/pages/dashboard.gohtml

112 lines
4.4 KiB
Plaintext

{{define "nodeCard"}}
<div class="col-12 col-md-6 col-xl-4 col-xxl-3 dashboard-node-card" data-node-search="{{lower .Name}} {{lower .IPAddress}} {{lower .Distro}} {{lower .GroupName}} {{lower .Tag}} {{lower .PackageManager}}">
<a class="card border-0 shadow-sm h-100 text-decoration-none node-chip" href="/nodes/{{.ID}}">
<div class="card-body p-0">
<div class="node-tile">
<div class="node-tile-icon">
<div class="chip-icon chip-icon-plain node-brand-icon">
{{if nodeIconPending .Distro .PackageManager}}
<i class="ti ti-loader-2 node-loading-icon"></i>
{{else}}
<i class="{{nodeIconClass .Distro .PackageManager}} distro-icon"></i>
{{end}}
</div>
</div>
<div class="node-tile-main">
<span class="node-status {{if .LastSeenAt}}is-online{{else}}is-offline{{end}}"></span>
<div class="node-tile-heading">
<h3 class="h6 mb-1 text-body-emphasis text-truncate">{{.Name}}</h3>
</div>
<div class="node-tile-metrics">
<div class="node-metric">
<span class="node-metric-label text-body-secondary">CPU</span>
<div class="progress" role="progressbar" aria-valuenow="{{printf "%.0f" .CPUUsage}}" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar" style="width: {{printf "%.0f" .CPUUsage}}%"></div>
</div>
<span class="node-metric-value text-body-emphasis">{{printf "%.0f" .CPUUsage}}%</span>
</div>
<div class="node-metric">
<span class="node-metric-label text-body-secondary">RAM</span>
<div class="progress" role="progressbar" aria-valuenow="{{printf "%.0f" .RAMUsage}}" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar bg-info" style="width: {{printf "%.0f" .RAMUsage}}%"></div>
</div>
<span class="node-metric-value text-body-emphasis">{{printf "%.0f" .RAMUsage}}%</span>
</div>
</div>
<div class="node-tile-meta d-flex justify-content-between small text-body-secondary mt-2 gap-2">
<span class="text-truncate"><i class="ti ti-world me-1"></i>{{.IPAddress}}</span>
<span class="text-nowrap"><i class="ti ti-clock-hour-4 me-1"></i>{{uptime .UptimeSeconds}}</span>
</div>
</div>
</div>
</div>
</a>
</div>
{{end}}
{{define "dashboardNodes"}}
{{$data := .Content}}
{{if and (eq (len $data.Groups) 0) (eq (len $data.Ungrouped) 0)}}
<section class="card border-0 shadow-sm">
<div class="card-body p-5 text-center">
<div class="chip-icon mx-auto mb-3">
<i class="ti ti-server-2"></i>
</div>
<h2 class="h4 mb-2">No Nodes Yet</h2>
<p class="text-body-secondary mb-4">Add your first VM to start tracking stats, commands, groups, and automations.</p>
{{if and .User (ne .User.Role "viewer")}}
<button class="btn btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#addVmModal">
<i class="ti ti-plus me-2"></i>Add VM
</button>
{{else}}
<div class="text-body-secondary small">You need editor access to add a VM.</div>
{{end}}
</div>
</section>
{{end}}
{{range $data.Groups}}
<section class="mb-4">
<div class="d-flex align-items-center justify-content-between mb-3">
<h2 class="h6 text-uppercase text-body-secondary mb-0 d-flex align-items-center gap-2">
<i class="{{.Icon}}"></i>
<span>{{.Name}}</span>
</h2>
<span class="small text-body-secondary">{{len .Nodes}}</span>
</div>
<div class="row g-3">
{{range .Nodes}}{{template "nodeCard" .}}{{end}}
</div>
</section>
{{end}}
{{if $data.Ungrouped}}
<section class="mb-4">
<div class="d-flex align-items-center justify-content-between mb-3">
<h2 class="h6 text-uppercase text-body-secondary mb-0">Ungrouped</h2>
<span class="small text-body-secondary">{{len $data.Ungrouped}}</span>
</div>
<div class="row g-3">
{{range $data.Ungrouped}}{{template "nodeCard" .}}{{end}}
</div>
</section>
{{end}}
{{end}}
{{define "content"}}
<section
id="dashboard-nodes"
data-dashboard-nodes-url="/dashboard/nodes"
class="dashboard-loader"
aria-live="polite"
>
<div class="card border-0 shadow-sm">
<div class="card-body py-5">
<div class="dashboard-spinner text-center">
<div class="spinner-border text-primary" role="status" aria-hidden="true"></div>
</div>
</div>
</div>
</section>
{{end}}