mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 07:17:17 +00:00
add dashboard
This commit is contained in:
parent
15ca143b70
commit
90bab813fe
@ -36,7 +36,9 @@
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div id="toolbar" class="dropdown">
|
<div id="toolbar" class="dropdown">
|
||||||
<a id="badge-status" tabindex="0" role="button" class="btn btn-outline-secondary" data-bs-toggle="popover" data-bs-trigger="focus" data-bs-content="no run data"><i class="bi bi-info-circle"></i></a>
|
<button id="dashboard-button" type="button" class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#dashboard-modal">
|
||||||
|
<i class="bi bi-info-circle"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
{% if not auth.enabled or auth.username is not none %}
|
{% if not auth.enabled or auth.username is not none %}
|
||||||
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
@ -152,6 +154,7 @@
|
|||||||
|
|
||||||
{% include "build-status/alerts.jinja2" %}
|
{% include "build-status/alerts.jinja2" %}
|
||||||
|
|
||||||
|
{% include "build-status/dashboard.jinja2" %}
|
||||||
{% include "build-status/package-add-modal.jinja2" %}
|
{% include "build-status/package-add-modal.jinja2" %}
|
||||||
{% include "build-status/package-rebuild-modal.jinja2" %}
|
{% include "build-status/package-rebuild-modal.jinja2" %}
|
||||||
{% include "build-status/key-import-modal.jinja2" %}
|
{% include "build-status/key-import-modal.jinja2" %}
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
<div id="dashboard-modal" tabindex="-1" role="dialog" class="modal fade">
|
||||||
|
<div class="modal-dialog modal-xl" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div id="dashboard-modal-header" class="modal-header">
|
||||||
|
<h4 class="modal-title">System health</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group row mt-2">
|
||||||
|
<div class="col-4 col-lg-2" style="text-align: right">Repository name</div>
|
||||||
|
<div id="dashboard-name" class="col-8 col-lg-3"></div>
|
||||||
|
<div class="col-4 col-lg-2" style="text-align: right">Repository architecture</div>
|
||||||
|
<div id="dashboard-architecture" class="col-8 col-lg-3"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row mt-2">
|
||||||
|
<div class="col-4 col-lg-2" style="text-align: right">Current status</div>
|
||||||
|
<div id="dashboard-status" class="col-8 col-lg-3"></div>
|
||||||
|
<div class="col-4 col-lg-2" style="text-align: right">Updated at</div>
|
||||||
|
<div id="dashboard-status-timestamp" class="col-8 col-lg-3"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dashboard-canvas" class="form-group row mt-2">
|
||||||
|
<div class="col-8 col-lg-6">
|
||||||
|
<canvas id="dashboard-packages-count-chart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="col-8 col-lg-6">
|
||||||
|
<canvas id="dashboard-packages-statuses-chart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i><span class="d-none d-sm-inline"> close</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const dashboardModal = document.getElementById("dashboard-modal");
|
||||||
|
const dashboardModalHeader = document.getElementById("dashboard-modal-header");
|
||||||
|
|
||||||
|
const dashboardName = document.getElementById("dashboard-name");
|
||||||
|
const dashboardArchitecture = document.getElementById("dashboard-architecture");
|
||||||
|
const dashboardStatus = document.getElementById("dashboard-status");
|
||||||
|
const dashboardStatusTimestamp = document.getElementById("dashboard-status-timestamp");
|
||||||
|
|
||||||
|
const dashboardCanvas = document.getElementById("dashboard-canvas");
|
||||||
|
const dashboardPackagesStatusesChartCanvas = document.getElementById("dashboard-packages-statuses-chart");
|
||||||
|
let dashboardPackagesStatusesChart = null;
|
||||||
|
const dashboardPackagesCountChartCanvas = document.getElementById("dashboard-packages-count-chart");
|
||||||
|
let dashboardPackagesCountChart = null;
|
||||||
|
|
||||||
|
ready(_ => {
|
||||||
|
dashboardPackagesStatusesChart = new Chart(dashboardPackagesStatusesChartCanvas, {
|
||||||
|
type: "pie",
|
||||||
|
data: {},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dashboardPackagesCountChart = new Chart(dashboardPackagesCountChartCanvas, {
|
||||||
|
type: "bar",
|
||||||
|
data: {},
|
||||||
|
options: {
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
@ -296,14 +296,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadPackage(packageBase, onFailure) {
|
function loadPackage(packageBase, onFailure) {
|
||||||
const headerClass = status => {
|
|
||||||
if (status === "pending") return ["bg-warning"];
|
|
||||||
if (status === "building") return ["bg-warning"];
|
|
||||||
if (status === "failed") return ["bg-danger", "text-white"];
|
|
||||||
if (status === "success") return ["bg-success", "text-white"];
|
|
||||||
return ["bg-secondary", "text-white"];
|
|
||||||
};
|
|
||||||
|
|
||||||
makeRequest(
|
makeRequest(
|
||||||
`/api/v1/packages/${packageBase}`,
|
`/api/v1/packages/${packageBase}`,
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// so far bootstrap-table only operates with jquery elements
|
// so far bootstrap-table only operates with jquery elements
|
||||||
const table = $(document.getElementById("packages"));
|
const table = $(document.getElementById("packages"));
|
||||||
|
|
||||||
const statusBadge = document.getElementById("badge-status");
|
const dashboardButton = document.getElementById("dashboard-button");
|
||||||
const versionBadge = document.getElementById("badge-version");
|
const versionBadge = document.getElementById("badge-version");
|
||||||
|
|
||||||
function doPackageAction(uri, packages, repository, successText, failureText, data) {
|
function doPackageAction(uri, packages, repository, successText, failureText, data) {
|
||||||
@ -141,14 +141,62 @@
|
|||||||
data => {
|
data => {
|
||||||
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
|
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
|
||||||
|
|
||||||
statusBadge.classList.remove(...statusBadge.classList);
|
dashboardButton.classList.remove(...dashboardButton.classList);
|
||||||
statusBadge.classList.add("btn");
|
dashboardButton.classList.add("btn");
|
||||||
statusBadge.classList.add(badgeClass(data.status.status));
|
dashboardButton.classList.add(badgeClass(data.status.status));
|
||||||
|
|
||||||
const popover = bootstrap.Popover.getOrCreateInstance(statusBadge);
|
dashboardModalHeader.classList.remove(...dashboardModalHeader.classList);
|
||||||
popover.dispose();
|
dashboardModalHeader.classList.add("modal-header");
|
||||||
statusBadge.dataset.bsContent = `${data.status.status} at ${new Date(1000 * data.status.timestamp).toISOStringShort()}`;
|
headerClass(data.status.status).forEach(clz => dashboardModalHeader.classList.add(clz));
|
||||||
bootstrap.Popover.getOrCreateInstance(statusBadge);
|
|
||||||
|
dashboardName.textContent = data.repository;
|
||||||
|
dashboardArchitecture.textContent = data.architecture;
|
||||||
|
dashboardStatus.textContent = data.status.status;
|
||||||
|
dashboardStatusTimestamp.textContent = new Date(1000 * data.status.timestamp).toISOStringShort();
|
||||||
|
|
||||||
|
if (dashboardPackagesStatusesChart) {
|
||||||
|
const labels = [
|
||||||
|
"unknown",
|
||||||
|
"pending",
|
||||||
|
"building",
|
||||||
|
"failed",
|
||||||
|
"success",
|
||||||
|
];
|
||||||
|
dashboardPackagesStatusesChart.config.data = {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: "packages in status",
|
||||||
|
data: labels.map(label => data.packages[label]),
|
||||||
|
backgroundColor: [
|
||||||
|
"rgb(55, 58, 60)",
|
||||||
|
"rgb(255, 117, 24)",
|
||||||
|
"rgb(255, 117, 24)",
|
||||||
|
"rgb(255, 0, 57)",
|
||||||
|
"rgb(63, 182, 24)", // copy-paste from current style
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
dashboardPackagesStatusesChart.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dashboardPackagesCountChart) {
|
||||||
|
dashboardPackagesCountChart.config.data = {
|
||||||
|
labels: ["packages"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "archives",
|
||||||
|
data: [data.stats.packages],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "bases",
|
||||||
|
data: [data.stats.bases],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
dashboardPackagesCountChart.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboardCanvas.hidden = data.status.total > 0;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -227,7 +275,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
bootstrap.Popover.getOrCreateInstance(statusBadge);
|
|
||||||
selectRepository();
|
selectRepository();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -58,6 +58,14 @@
|
|||||||
return value.includes(dataList[index].toLowerCase());
|
return value.includes(dataList[index].toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function headerClass(status) {
|
||||||
|
if (status === "pending") return ["bg-warning"];
|
||||||
|
if (status === "building") return ["bg-warning"];
|
||||||
|
if (status === "failed") return ["bg-danger", "text-white"];
|
||||||
|
if (status === "success") return ["bg-success", "text-white"];
|
||||||
|
return ["bg-secondary", "text-white"];
|
||||||
|
}
|
||||||
|
|
||||||
function listToTable(data) {
|
function listToTable(data) {
|
||||||
return Array.from(new Set(data))
|
return Array.from(new Set(data))
|
||||||
.sort()
|
.sort()
|
||||||
|
@ -25,6 +25,6 @@ class FileSchema(Schema):
|
|||||||
request file upload schema
|
request file upload schema
|
||||||
"""
|
"""
|
||||||
|
|
||||||
archive = fields.Field(required=True, metadata={
|
archive = fields.Raw(required=True, metadata={
|
||||||
"description": "Package archive to be uploaded",
|
"description": "Package archive to be uploaded",
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user