Skip to content

Commit 936f1d5

Browse files
authored
Merge pull request marcpope#207 from c0dr1ver/fix/queue-duration-hours
Show hours in queue duration
2 parents 41f0e90 + 606ddfb commit 936f1d5

1 file changed

Lines changed: 32 additions & 10 deletions

File tree

src/Views/queue/index.php

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
<?php
2-
$avgDur = '--';
3-
if ($avgSec > 0) {
4-
if ($avgSec < 60) $avgDur = $avgSec . 's';
5-
elseif ($avgSec < 3600) $avgDur = round($avgSec / 60) . 'm';
6-
else $avgDur = round($avgSec / 3600, 1) . 'h';
2+
function formatDurationLabel(int $s): string {
3+
return $s >= 3600 ? floor($s / 3600) . 'h ' . floor(($s % 3600) / 60) . 'm ' . ($s % 60) . 's' : ($s >= 60 ? floor($s / 60) . 'm ' . ($s % 60) . 's' : $s . 's');
4+
}
5+
6+
$avgDur = $avgSec > 0 ? formatDurationLabel((int) $avgSec) : '--';
7+
$maxCompletedDuration = max(array_map(fn($j) => (int) ($j['duration_seconds'] ?? 0), $completed ?: [['duration_seconds' => 0]]));
8+
9+
function durationBarHtml(int $duration, int $maxDuration): string {
10+
$pct = $maxDuration > 0 ? min(100, round(($duration / $maxDuration) * 100)) : 0;
11+
$hue = 120 - round($pct * 1.2);
12+
$label = formatDurationLabel($duration);
13+
return '<div class="progress position-relative" style="height:20px;min-width:120px;" title="' . htmlspecialchars($label) . '">'
14+
. '<div class="progress-bar" style="width:' . $pct . '%;background-color:hsl(' . $hue . ',70%,45%);"></div>'
15+
. '<span class="position-absolute top-50 start-50 translate-middle small fw-semibold px-2 rounded bg-body text-body border text-nowrap">' . htmlspecialchars($label) . '</span>'
16+
. '</div>';
717
}
818

919
// Job type icons mapping
@@ -196,7 +206,7 @@ function jobTypeIcon(string $type): string {
196206
<td class="d-none d-md-table-cell">
197207
<?php
198208
$d = $job['duration_seconds'] ?? 0;
199-
echo $d >= 60 ? floor($d / 60) . 'm ' . ($d % 60) . 's' : $d . 's';
209+
echo durationBarHtml((int) $d, $maxCompletedDuration);
200210
?>
201211
</td>
202212
<td class="text-center">
@@ -253,7 +263,18 @@ function formatDate(d) {
253263

254264
function formatDuration(s) {
255265
s = parseInt(s) || 0;
256-
return s >= 60 ? Math.floor(s / 60) + 'm ' + (s % 60) + 's' : s + 's';
266+
return s >= 3600 ? Math.floor(s / 3600) + 'h ' + Math.floor((s % 3600) / 60) + 'm ' + (s % 60) + 's' : (s >= 60 ? Math.floor(s / 60) + 'm ' + (s % 60) + 's' : s + 's');
267+
}
268+
269+
function durationBar(s, maxS) {
270+
s = parseInt(s) || 0;
271+
maxS = parseInt(maxS) || 0;
272+
const pct = maxS > 0 ? Math.min(100, Math.round((s / maxS) * 100)) : 0;
273+
const hue = 120 - Math.round(pct * 1.2);
274+
const label = formatDuration(s);
275+
return '<div class="progress position-relative" style="height:20px;min-width:120px;" title="' + esc(label) + '">' +
276+
'<div class="progress-bar" style="width:' + pct + '%;background-color:hsl(' + hue + ',70%,45%);"></div>' +
277+
'<span class="position-absolute top-50 start-50 translate-middle small fw-semibold px-2 rounded bg-body text-body border text-nowrap">' + esc(label) + '</span></div>';
257278
}
258279

259280
function statusBadge(status) {
@@ -313,7 +334,7 @@ function buildInProgressRow(job) {
313334
'<td class="text-end" onclick="event.stopPropagation()">' + actions + '</td></tr>';
314335
}
315336

316-
function buildCompletedRow(job) {
337+
function buildCompletedRow(job, maxDuration) {
317338
let statusHtml;
318339
if (job.status === 'completed' && job.had_warnings) {
319340
statusHtml = '<i class="bi bi-exclamation-triangle-fill text-warning" data-bs-toggle="tooltip" title="' + esc('Completed with warnings: ' + String(job.error_log || '').substring(0, 200)) + '"></i>';
@@ -339,7 +360,7 @@ function buildCompletedRow(job) {
339360
'<td class="text-nowrap">' + jobTypeIcon(job.task_type) + esc(job.task_type) + '</td>' +
340361
'<td class="d-none d-md-table-cell">' + Number(job.files_total || 0).toLocaleString() + '</td>' +
341362
'<td class="d-none d-md-table-cell">' + esc(job.repo_name || '--') + '</td>' +
342-
'<td class="d-none d-md-table-cell">' + formatDuration(job.duration_seconds) + '</td>' +
363+
'<td class="d-none d-md-table-cell">' + durationBar(job.duration_seconds, maxDuration) + '</td>' +
343364
'<td class="text-center">' + statusHtml + '</td>' +
344365
'<td class="text-end" onclick="event.stopPropagation()">' + actions + '</td></tr>';
345366
}
@@ -369,7 +390,8 @@ function refreshQueue() {
369390
let html = '<div class="table-responsive"><table class="table table-hover align-middle mb-0"><thead class="table-light"><tr>' +
370391
'<th>Date</th><th>Client</th><th>Task</th><th class="d-none d-md-table-cell">Files</th><th class="d-none d-md-table-cell">Repo</th><th class="d-none d-md-table-cell">Duration</th><th class="text-center">Status</th><th style="width:80px;"></th>' +
371392
'</tr></thead><tbody>';
372-
data.completed.forEach(j => html += buildCompletedRow(j));
393+
const maxDuration = Math.max(0, ...data.completed.map(j => parseInt(j.duration_seconds) || 0));
394+
data.completed.forEach(j => html += buildCompletedRow(j, maxDuration));
373395
html += '</tbody></table></div>';
374396
cCard.innerHTML = html;
375397
}

0 commit comments

Comments
 (0)