improve redfish collection progress and robust hardware dedup/serial parsing

This commit is contained in:
2026-02-28 16:07:42 +03:00
parent 8dbbec3610
commit 9a30705c9a
9 changed files with 871 additions and 60 deletions

View File

@@ -242,6 +242,28 @@ main {
font-size: 0.9rem;
}
.job-progress {
height: 22px;
border-radius: 999px;
border: 1px solid #cbd5e1;
background: #e2e8f0;
overflow: hidden;
margin-bottom: 0.8rem;
}
.job-progress-bar {
height: 100%;
min-width: 2.5rem;
background: linear-gradient(90deg, #2563eb, #0ea5e9);
color: #fff;
font-size: 0.78rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
transition: width 0.25s ease;
}
.meta-label {
color: #64748b;
font-weight: 600;

View File

@@ -334,9 +334,11 @@ function renderCollectionJob() {
const jobIdValue = document.getElementById('job-id-value');
const statusValue = document.getElementById('job-status-value');
const progressValue = document.getElementById('job-progress-value');
const etaValue = document.getElementById('job-eta-value');
const progressBar = document.getElementById('job-progress-bar');
const logsList = document.getElementById('job-logs-list');
const cancelButton = document.getElementById('cancel-job-btn');
if (!jobStatusBlock || !jobIdValue || !statusValue || !progressValue || !logsList || !cancelButton) {
if (!jobStatusBlock || !jobIdValue || !statusValue || !progressValue || !etaValue || !progressBar || !logsList || !cancelButton) {
return;
}
@@ -356,12 +358,16 @@ function renderCollectionJob() {
failed: 'Сбор завершился ошибкой',
canceled: 'Сбор отменен'
}[collectionJob.status];
const progressLabel = isTerminal
? terminalMessage
: latestCollectionActivityMessage();
progressValue.textContent = `${collectionJob.progress}% · ${progressLabel}`;
const activity = isTerminal ? terminalMessage : latestCollectionActivityMessage();
const eta = isTerminal ? '-' : latestCollectionETA();
const progressPercent = Math.max(0, Math.min(100, Number(collectionJob.progress) || 0));
logsList.innerHTML = collectionJob.logs.map((log) => (
progressValue.textContent = activity;
etaValue.textContent = eta;
progressBar.style.width = `${progressPercent}%`;
progressBar.textContent = `${progressPercent}%`;
logsList.innerHTML = [...collectionJob.logs].reverse().map((log) => (
`<li><span class="log-time">${escapeHtml(log.time)}</span><span class="log-message">${escapeHtml(log.message)}</span></li>`
)).join('');
@@ -379,7 +385,27 @@ function latestCollectionActivityMessage() {
}
// Job logs already contain server timestamp prefix. Show concise step text in progress label.
const cleaned = last.replace(/^\d{4}-\d{2}-\d{2}T[^\s]+\s+/, '').trim();
return cleaned || 'Сбор данных...';
if (!cleaned) {
return 'Сбор данных...';
}
return cleaned.replace(/\s*[,(]?\s*ETA[^,;)]*/i, '').trim() || 'Сбор данных...';
}
function latestCollectionETA() {
if (!collectionJob || !Array.isArray(collectionJob.logs) || collectionJob.logs.length === 0) {
return '-';
}
const last = String(collectionJob.logs[collectionJob.logs.length - 1].message || '').trim();
const cleaned = last.replace(/^\d{4}-\d{2}-\d{2}T[^\s]+\s+/, '').trim();
if (!cleaned) {
return '-';
}
const match = cleaned.match(/ETA[^,;)]*/i);
if (!match) {
return '-';
}
const eta = match[0].replace(/^ETA\s*[:=~≈-]?\s*/i, '').trim();
return eta || '-';
}
function isCollectionJobTerminal(status) {

View File

@@ -78,7 +78,11 @@
<span class="meta-label">Статус:</span>
<span id="job-status-value" class="job-status-badge">Queued</span>
</div>
<div><span class="meta-label">Прогресс:</span> <span id="job-progress-value">0% · Шаг 0 из 4</span></div>
<div><span class="meta-label">Этап:</span> <span id="job-progress-value">Сбор данных...</span></div>
<div><span class="meta-label">ETA:</span> <span id="job-eta-value">-</span></div>
</div>
<div class="job-progress" aria-label="Прогресс задачи">
<div id="job-progress-bar" class="job-progress-bar" style="width: 0%">0%</div>
</div>
<div class="job-status-logs">
<p class="meta-label">Журнал шагов:</p>