You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.0 KiB
143 lines
5.0 KiB
{% extends "base.html" %}
|
|
{% block content %}
|
|
<h1>{{PAGE_TITLE}}</h1>
|
|
<ul class="nav nav-tabs">
|
|
<li class="nav-item">
|
|
{% if PAGE_TYPE == 'running' %}
|
|
<a class="nav-link active" aria-current="page" href="/tasks">Running</a>
|
|
{% else %}
|
|
<a class="nav-link" href="/tasks">Running</a>
|
|
{% endif %}
|
|
</li>
|
|
<li class="nav-item">
|
|
{% if PAGE_TYPE == 'queued' %}
|
|
<a class="nav-link active" aria-current="page" href="/tasks?type=queued">Queued</a>
|
|
{% else %}
|
|
<a class="nav-link" href="/tasks?type=queued">Queued</a>
|
|
{% endif %}
|
|
</li>
|
|
<li class="nav-item">
|
|
{% if PAGE_TYPE == 'complete' %}
|
|
<a class="nav-link active" aria-current="page" href="/tasks?type=complete">Complete</a>
|
|
{% else %}
|
|
<a class="nav-link" href="/tasks?type=complete">Complete</a>
|
|
{% endif %}
|
|
</li>
|
|
</ul>
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-bordered">
|
|
<thead class="table-dark">
|
|
<tr>
|
|
<th scope="col">Score</th>
|
|
<th scope="col">Queued</th>
|
|
<th scope="col">Package</th>
|
|
<th scope="col">Status</th>
|
|
{% if PAGE_TYPE != 'queued' %}
|
|
<th scope="col">Log</th>
|
|
{% endif %}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for task in tasks %}
|
|
<tr>
|
|
<td>{{ task.score }}</td>
|
|
<td>
|
|
{% if PAGE_TYPE == 'running' %}
|
|
Started at <span data-timestamp="{{ task.start_timestamp }}"></span><br />
|
|
(Duration: <span data-timedelta="{{ task.running_timedelta }}"></span>)
|
|
{% elif PAGE_TYPE == 'queued' %}
|
|
<span data-timestamp="{{ task.queued_timestamp }}"></span>
|
|
{% else %}
|
|
{% if task.successful == 'true' %}
|
|
<i class="fas fa-check" style="color: green;"></i> <b>Task Succeeded</b><br />
|
|
{% else %}
|
|
<i class="fas fa-times-circle" style="color: red;"></i> <b>Task Failed</b><br />
|
|
{% endif %}
|
|
Started at <span data-timestamp="{{ task.start_timestamp }}"></span><br />
|
|
Finished at <span data-timestamp="{{ task.finish_timestamp }}"></span><br />
|
|
(Duration: <span data-timedelta="{{ task.running_timedelta }}"></span>)
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
Name: {{ task.package_name }}<br />
|
|
Release: {{ task.package_codename }}
|
|
</td>
|
|
<td>{{ task.job_status }}</td>
|
|
{% if PAGE_TYPE != 'queued' %}
|
|
<td>
|
|
<div class="bg-light font-monospace p-2 rounded overflow-scroll" style="max-height: 15em; white-space: pre-wrap;">{{ task.log }}</div>
|
|
</td>
|
|
{% endif %}
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<script>
|
|
function formatDuration(ms) {
|
|
if (typeof ms !== "number" || ms < 0) {
|
|
throw new Error("Input must be a non-negative number representing milliseconds.");
|
|
}
|
|
|
|
// statics
|
|
const millisecondsInOneSecond = 1000;
|
|
const millisecondsInOneMinute = 60 * millisecondsInOneSecond;
|
|
const millisecondsInOneHour = 60 * millisecondsInOneMinute;
|
|
const millisecondsInOneDay = 24 * millisecondsInOneHour;
|
|
|
|
// calculate
|
|
const days = Math.floor(ms / millisecondsInOneDay);
|
|
const hours = Math.floor((ms % millisecondsInOneDay) / millisecondsInOneHour);
|
|
const minutes = Math.floor((ms % millisecondsInOneHour) / millisecondsInOneMinute);
|
|
const seconds = Math.floor((ms % millisecondsInOneMinute) / millisecondsInOneSecond);
|
|
const milliseconds = ms % millisecondsInOneSecond;
|
|
|
|
/**
|
|
* Pads a number with leading zeros to achieve the desired length.
|
|
*
|
|
* @param {number} num - The number to pad.
|
|
* @param {number} size - The desired string length.
|
|
* @returns {string} - The padded string.
|
|
*/
|
|
const pad = (num, size) => {
|
|
let s = num.toString();
|
|
while (s.length < size) s = "0" + s;
|
|
return s;
|
|
};
|
|
|
|
// Construct the formatted string
|
|
let formatted = "";
|
|
|
|
if (days > 0) {
|
|
formatted += `${days}:`;
|
|
}
|
|
|
|
formatted += `${pad(hours, 2)}:${pad(minutes, 2)}:${pad(seconds, 2)}.${pad(milliseconds, 3)}`;
|
|
|
|
return formatted;
|
|
}
|
|
|
|
document.querySelectorAll("[data-timestamp]").forEach((el) => {
|
|
const timestamp = parseInt(el.getAttribute("data-timestamp"), 10);
|
|
|
|
if (!isNaN(timestamp)) {
|
|
const date = new Date(timestamp);
|
|
const formattedDate = date.toLocaleString(undefined, {
|
|
timeZoneName: "short"
|
|
});
|
|
el.textContent = formattedDate;
|
|
}
|
|
});
|
|
|
|
document.querySelectorAll("[data-timedelta]").forEach((el) => {
|
|
const timestamp = parseInt(el.getAttribute("data-timedelta"));
|
|
|
|
if (!isNaN(timestamp)) {
|
|
el.textContent = formatDuration(timestamp);
|
|
}
|
|
});
|
|
|
|
</script>
|
|
{% endblock %}
|