Move Check updates into action bar and report results in the tray.
Release rolling / release (push) Successful in 11m35s

This commit is contained in:
Raven Scott
2026-07-16 00:17:26 -04:00
parent 645f025042
commit dfa0b3dcd6
2 changed files with 38 additions and 26 deletions
+35 -18
View File
@@ -8590,7 +8590,12 @@ document.addEventListener('DOMContentLoaded', () => {
if (typeof window.refreshRegistryPanel === 'function') window.refreshRegistryPanel();
});
document.getElementById('check-image-updates-btn')?.addEventListener('click', () => {
scheduleImageUpdateCheck({ force: true, clearCache: true, immediate: true });
scheduleImageUpdateCheck({
force: true,
clearCache: true,
immediate: true,
notify: true,
});
});
// Prefer smart network modal for create buttons
@@ -9712,7 +9717,8 @@ function ensureInitialImageUpdateCheck() {
if (!peerId) return;
if (imageUpdateInitialPeerId === peerId) return;
imageUpdateInitialPeerId = peerId;
scheduleImageUpdateCheck({ force: false, immediate: true, initial: true });
// Silent: table indicators only — no tray spam on Containers tab open
scheduleImageUpdateCheck({ force: false, immediate: true, initial: true, silent: true });
}
async function runImageUpdateCheck(opts = {}) {
@@ -9720,13 +9726,16 @@ async function runImageUpdateCheck(opts = {}) {
if (currentView && currentView !== 'containers' && !opts.force) return;
if (imageUpdateCheckInFlight && !opts.force) return;
imageUpdateCheckInFlight = true;
// Tray only for explicit user-triggered checks — suppress on page-load / background
const notify =
opts.notify === true || (opts.force === true && opts.initial !== true && opts.silent !== true);
const silent = opts.silent === true || opts.initial === true || !notify;
const btn = document.getElementById('check-image-updates-btn');
const line = document.getElementById('image-update-status-line');
if (btn) {
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-sync-alt fa-spin me-1"></i>Checking…';
btn.innerHTML = '<i class="fas fa-sync-alt fa-spin"></i><span>Checking…</span>';
}
if (line) line.textContent = 'Checking image digests against registries…';
// Mark visible rows as checking on force or first tab load (no client cache yet)
const listElement = domCache.containerList || containerList;
@@ -9765,12 +9774,12 @@ async function runImageUpdateCheck(opts = {}) {
applyImageUpdateToRow(row, row._pdContainer);
});
}
const statuses = Object.values(byImage);
const outdated = statuses.filter((s) => s.status === 'outdated').length;
const updated = statuses.filter((s) => s.status === 'updated').length;
const unknown = statuses.filter((s) => s.status === 'unknown' || s.status === 'skipped').length;
const withErr = statuses.filter((s) => s.error).slice(0, 2);
if (line) {
if (!silent) {
const statuses = Object.values(byImage);
const outdated = statuses.filter((s) => s.status === 'outdated').length;
const updated = statuses.filter((s) => s.status === 'updated').length;
const unknown = statuses.filter((s) => s.status === 'unknown' || s.status === 'skipped').length;
const withErr = statuses.filter((s) => s.error).slice(0, 2);
let text =
outdated > 0
? `${outdated} image(s) have updates · ${updated} up to date · ${unknown} unknown/skipped`
@@ -9782,20 +9791,28 @@ async function runImageUpdateCheck(opts = {}) {
if (withErr.length) {
text += `${withErr.map((s) => s.error).join('; ')}`;
}
line.textContent = text;
line.title = statuses
.filter((s) => s.error)
.map((s) => `${s.image}: ${s.error}`)
.join('\n') || text;
const trayType = outdated > 0 ? 'warning' : withErr.length ? 'warning' : 'info';
if (typeof notificationManager?.add === 'function') {
notificationManager.add(trayType, text, { badge: outdated > 0 });
} else if (typeof showAlert === 'function') {
showAlert(trayType, text);
}
}
} catch (err) {
if (line) line.textContent = err?.message || 'Update check failed';
console.warn('[image-updates]', err);
if (!silent) {
const msg = err?.message || 'Update check failed';
if (typeof notificationManager?.add === 'function') {
notificationManager.add('danger', msg, { badge: true });
} else if (typeof showAlert === 'function') {
showAlert('danger', msg);
}
}
} finally {
imageUpdateCheckInFlight = false;
if (btn) {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-sync-alt me-1"></i>Check updates';
btn.innerHTML = '<i class="fas fa-sync-alt"></i><span>Check updates</span>';
}
}
}
+3 -8
View File
@@ -999,20 +999,15 @@
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="window.pruneResource && window.pruneResource('containers')" data-min-role="admin" title="Prune stopped containers">
<i class="fas fa-broom"></i><span>Prune</span>
</button>
<button type="button" class="btn btn-sm btn-outline-info" id="check-image-updates-btn" title="Recheck registry digests for all containers">
<i class="fas fa-sync-alt"></i><span>Check updates</span>
</button>
<button type="button" class="btn btn-sm btn-outline-secondary containers-action-btn" data-bulk-op="clear" onclick="clearContainerSelection()" title="Clear selection" disabled>
<i class="fas fa-times"></i><span>Clear</span>
</button>
</div>
</div>
</div>
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-2">
<p class="small text-muted mb-0" id="image-update-status-line">
Image updates: indicators compare local digests to the registry .
</p>
<button type="button" class="btn btn-sm btn-outline-info" id="check-image-updates-btn" title="Recheck registry digests for all containers">
<i class="fas fa-sync-alt me-1"></i>Check updates
</button>
</div>
<div class="table-responsive">
<table class="table table-dark table-striped" id="containers-table">
<thead>