1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 03:36:48 +00:00
webvirtcloud/computes/templates/overview.html
catborise 65c5a251ba style(computes,networks,storages,interfaces): the cards' rows tighter
The label and value rows of the host pages' cards (Overview, storage
pools, networks, interfaces) take Bootstrap's py-1 instead of the list
group's own padding, as the interface list's cards already do: about
half the height a row, the same on every page. A pool's space bar keeps
its padding.
2026-10-29 10:10:04 +03:00

254 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% load i18n %}
{% load static %}
{% load bootstrap_icons %}
{% block title %}{% trans "Overview" %} - {{ compute.name }}{% endblock %}
{% block page_heading_extra %}
<a class="btn btn-sm btn-outline-primary" href="{% url 'compute_update' compute.id %}">{% bs_icon 'pencil' %} {% trans "Edit connection" %}</a>
<a class="btn btn-sm btn-outline-danger" href="{% url 'compute_delete' compute.id %}">{% bs_icon 'x-circle' %} {% trans "Remove from panel" %}</a>
{% endblock page_heading_extra %}
{% block page_heading %}{{ compute.name }}{% endblock page_heading %}
{% block content %}
<div id="host_status" class="d-flex flex-wrap align-items-baseline column-gap-3 text-body-secondary mb-3">
<span>
{% if connected %}
<span class="d-inline-block rounded-circle p-1 flex-shrink-0 bg-success" aria-hidden="true"></span> <span class="text-body">{% trans "Connected" %}</span>
{% else %}
<span class="d-inline-block rounded-circle p-1 flex-shrink-0 bg-danger" aria-hidden="true"></span> <span class="text-body">{% trans "Not connected" %}</span>
{% endif %}
</span>
<span class="text-break">{{ compute.hostname }}</span>
{% if compute.details %}<span class="text-break">{{ compute.details }}</span>{% endif %}
</div>
{% include "computes/host_nav.html" with section="overview" %}
{% if not connected %}
<div class="alert alert-warning" role="alert">
<div class="mb-2">{% trans "The panel cannot reach this host, so its VMs, capacity and load are not shown:" %} {{ compute.connection_error }}</div>
<a class="btn btn-sm btn-warning" href="{% url 'overview' compute.id %}">{% bs_icon 'arrow-clockwise' %} {% trans "Try again" %}</a>
<a class="btn btn-sm btn-outline-secondary" href="{% url 'compute_update' compute.id %}">{% trans "Edit connection" %}</a>
</div>
{% else %}
{% if read_error %}
<div class="alert alert-warning" role="alert">{% trans "The host's details could not be read:" %} {{ read_error }}</div>
{% endif %}
{% if given %}
<div class="row row-cols-1 row-cols-sm-2 row-cols-xl-4 g-3 mb-4">
<div class="col">
<div class="card h-100">
<div class="card-header">{% bs_icon 'server' %} {% trans "VMs" %}</div>
<div class="card-body">
<div class="fs-4 lh-sm">{{ given.vm_count }}</div>
<div class="small text-body-secondary">
{% blocktrans with running=given.vms.running shutoff=given.vms.shutoff %}{{ running }} running, {{ shutoff }} shut off{% endblocktrans %}{% if given.vms.paused %}, {% blocktrans with paused=given.vms.paused %}{{ paused }} paused{% endblocktrans %}{% endif %}{% if given.vms.other %}, {% blocktrans with other=given.vms.other %}{{ other }} other{% endblocktrans %}{% endif %}
</div>
<a class="small" href="{% url 'instances' compute.id %}">{% trans "Instances" %} &rarr;</a>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<div class="card-header">{% bs_icon 'cpu' %} {% trans "vCPUs" %}</div>
<div class="card-body">
{% include "computes/capacity_vcpus.html" %}
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<div class="card-header">{% bs_icon 'memory' %} {% trans "Memory" %}</div>
<div class="card-body">
{% include "computes/capacity_memory.html" %}
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<div class="card-header">{% bs_icon 'device-hdd' %} {% trans "Storage" %}</div>
<div class="card-body">
{% include "computes/capacity_storage.html" %}
<a class="small" href="{% url 'storages' compute.id %}">{% trans "Storages" %} &rarr;</a>
</div>
</div>
</div>
</div>
{% else %}
<div class="text-body-secondary mb-4">{% trans "The capacity could not be read." %}</div>
{% endif %}
{# the load is read on its own: shown also when the details could not be #}
<div class="row g-3">
<div class="col-lg-6">
<div class="card h-100">
<div class="card-header d-flex justify-content-between">
<span>{% bs_icon 'speedometer2' %} {% trans "CPU in use" %}</span> <span id="cpu_now" class="fw-semibold">&ndash;</span>
</div>
<div class="card-body">
<div class="chart position-relative"><canvas id="cpuChart" role="img" aria-label="{% trans "CPU in use, recent readings" %}"></canvas></div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card h-100">
<div class="card-header d-flex justify-content-between">
<span>{% bs_icon 'memory' %} {% trans "Memory in use" %}</span> <span id="mem_now" class="fw-semibold">&ndash;</span>
</div>
<div class="card-body">
<div class="chart position-relative"><canvas id="memChart" role="img" aria-label="{% trans "Memory in use, recent readings" %}"></canvas></div>
</div>
</div>
</div>
</div>
<div class="small text-body-secondary mt-2 mb-4">
{% trans "The last 10 readings, one every 5 seconds. Memory in use leaves out the host's buffers and cache." %}
<span id="graph_state" data-updated="{% trans "Updated at %(time)s." %}"
data-stale="{% trans "Not updated since %(time)s: the host did not answer." %}">{% trans "Waiting for the first reading." %}</span>
</div>
{% if host %}
<div class="row g-3 mb-4">
<div class="col-lg-6">
<div class="card h-100">
<div class="card-header">{% bs_icon 'cpu' %} {% trans "Hardware" %}</div>
<ul class="list-group list-group-flush">
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Processor" %}</span>
<span class="text-end text-break">{{ host.processor|default:"–" }}</span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Architecture" %}</span>
<span class="text-end text-break">{{ host.arch }}</span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Logical CPUs" %}</span>
<span class="text-end text-break"><span class="fw-semibold">{{ host.topology.cpus }}</span></span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Physical cores" %}</span>
<span class="text-end text-break"><span class="fw-semibold">{{ host.topology.cores|default:"–" }}</span></span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Sockets" %}</span>
<span class="text-end text-break"><span class="fw-semibold">{{ host.topology.sockets|default:"–" }}</span></span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "NUMA nodes" %}</span>
<span class="text-end text-break"><span class="fw-semibold">{{ host.topology.nodes|default:"–" }}</span></span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Clock" %}</span>
<span class="text-end text-break">{{ host.ghz }} GHz</span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Memory" %}</span>
<span class="text-end text-break"><span class="fw-semibold">{{ host.memory|filesizeformat }}</span></span>
</li>
</ul>
</div>
</div>
<div class="col-lg-6">
<div class="card h-100">
<div class="card-header">{% bs_icon 'layers' %} {% trans "Software and connection" %}</div>
<ul class="list-group list-group-flush">
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Hostname" %}</span>
<span class="text-end text-break">{{ host.hostname }}</span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{{ host.hypervisor }}</span>
<span class="text-end text-break"><span class="badge text-bg-primary">{{ host.hypervisor_version }}</span></span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">libvirt</span>
<span class="text-end text-break"><span class="badge text-bg-primary">{{ host.libvirt_version }}</span></span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Guest architectures" %}</span>
<span class="text-end text-break">{% for arch, types in host.guest_archs.items %}<span class="badge text-bg-light border ms-1">{{ arch }} <span class="fw-normal text-body-secondary">{{ types|join:" · " }}</span></span>{% endfor %}</span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Emulator" %}</span>
<span class="text-end text-break"><code>{{ host.emulator|default:"–" }}</code></span>
</li>
<li class="list-group-item py-1 d-flex justify-content-between align-items-baseline gap-3">
<span class="text-body-secondary">{% trans "Connection" %}</span>
<span class="text-end text-break"><code>{{ host.uri }}</code></span>
</li>
</ul>
</div>
</div>
</div>
{% endif %}
{% endif %}
{% endblock %}
{% block script %}
{% if connected %}
<script src="{% static "js/chart.umd.min.js" %}"></script>
<script src="{% static "js/charts.js" %}"></script>
<script src="{% static "js/poll.js" %}"></script>
<script>
{% trans "average over" as average_over %}
// the seconds each CPU point averages
var cpuWindows = [];
var cpuChart = lineChart(document.getElementById("cpuChart"), "%", ["Usage"], {
max: 100,
tooltip: function (context, text) {
var span = cpuWindows[context.dataIndex];
return span ? text + ' ({{ average_over|escapejs }} ' + span + ' s)' : text;
},
});
var memChart = lineChart(document.getElementById("memChart"), "GB", ["Usage"]);
var cpuNow = document.getElementById("cpu_now");
var memNow = document.getElementById("mem_now");
var state = document.getElementById("graph_state");
var lastUpdate = "–";
function gb(bytes) {
return Math.round(bytes / 107374182.4) / 10;
}
// a failed reading leaves the charts as they were: say since when
function stale() {
state.textContent = state.dataset.stale.replace("%(time)s", lastUpdate);
state.classList.add("text-danger");
}
// the CPU sample of the previous answer: usage is taken since then
var cpuSample = null;
pollWhileVisible(5000, function () {
return $.getJSON('{% url 'compute_graph' compute.id %}', cpuSample ? {cpu_sample: cpuSample} : {}).fail(stale);
}, function (data) {
cpuSample = data.cpu_sample || null;
cpuWindows.push(data.window);
if (cpuWindows.length > CHART_POINTS) {
cpuWindows.shift();
}
addPoint(cpuChart, data.timeline, [data.cpudata]);
// a host that could not be read gives no values: a gap, same axis
if (data.memdata.total) {
memChart.options.scales.y.max = gb(data.memdata.total);
addPoint(memChart, data.timeline, [gb(data.memdata.usage)]);
memNow.textContent = gb(data.memdata.usage) + " / " + gb(data.memdata.total) + " GB";
} else {
addPoint(memChart, data.timeline, [null]);
}
if (data.cpudata == null) {
stale();
return;
}
cpuNow.textContent = data.cpudata + " %";
lastUpdate = data.timeline;
state.textContent = state.dataset.updated.replace("%(time)s", data.timeline);
state.classList.remove("text-danger");
}, 0);
</script>
{% endif %}
{% endblock %}