feat: execution failure reports, auto-printer for WMT, UTC timezone fix for all timestamps

This commit is contained in:
ske087
2026-04-24 15:52:12 +03:00
parent d2485e4c66
commit 056f467791
27 changed files with 1391 additions and 285 deletions

View File

@@ -21,9 +21,11 @@
{% for g in inventory.groups.values() %}{% set ns.total = ns.total + g.hosts|length %}{% endfor %}
<span class="badge bg-primary ms-2">{{ ns.total }}</span>
</span>
<div class="d-flex gap-1">
<button class="btn btn-sm btn-success" onclick="syncDevices()">
<i class="fas fa-sync-alt me-1"></i>Sync All
<div class="d-flex align-items-center gap-1">
<span id="lastSyncedLabel" class="text-muted me-1" style="font-size:.72rem;"></span>
<button class="btn btn-sm btn-success" onclick="syncDevices()" id="syncBtn"
title="Pull latest hostnames &amp; IPs from the monitoring database">
<i class="fas fa-database me-1"></i>Sync IPs from DB
</button>
<button class="btn btn-sm btn-outline-secondary" onclick="toggleRaw()" title="Raw YAML">
<i class="fas fa-code"></i>
@@ -87,7 +89,7 @@
{% else %}
<div class="card-body text-center py-5 text-muted">
<i class="fas fa-box-open fa-3x mb-3"></i>
<p class="mb-0">Inventory is empty. Use <strong>Sync All</strong> or add from below.</p>
<p class="mb-0">Inventory is empty. Click <strong>Sync IPs from DB</strong> to import all active devices.</p>
</div>
{% endif %}
</div>
@@ -414,22 +416,24 @@ function togglePwField(val) {
document.getElementById('pwField').classList.toggle('d-none', val !== 'password');
}
/* ── Sync all DB devices into monitoring_devices ── */
/* ── Sync IPs from monitoring DB into inventory ── */
async function syncDevices() {
const btn = event.currentTarget;
const btn = document.getElementById('syncBtn');
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Syncing…';
try {
const r = await fetch(`${API}/inventory/sync`, {method:'POST'});
const d = await r.json();
if (d.success) {
const now = new Date().toLocaleTimeString();
document.getElementById('lastSyncedLabel').textContent = `Last synced: ${now}`;
showAlert(`<i class="fas fa-check-circle me-1"></i> ${d.message}`, 'success');
setTimeout(() => location.reload(), 1200);
} else { showAlert(`Sync failed: ${d.error}`, 'danger'); }
} catch { showAlert('Network error', 'danger'); }
finally {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-sync-alt me-1"></i>Sync All';
btn.innerHTML = '<i class="fas fa-database me-1"></i>Sync IPs from DB';
}
}