Skip to content

Commit f4b2332

Browse files
authored
Merge pull request redenfire#33 from NeoMod/pr/feat-ui-update-controls
feat: improve update controls and badges
2 parents 0678617 + f97c3cb commit f4b2332

1 file changed

Lines changed: 32 additions & 5 deletions

File tree

‎web/index.html‎

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
.group-row + .child-row td { padding-top: 2px; }
1919
.child-row td:first-child { padding-left: 28px; }
2020
.child-row:last-child td { border-bottom: 1px solid #334155; }
21-
.badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: .75rem; font-weight: 600; }
21+
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 4px 12px; border-radius: 999px; font-size: .85rem; font-weight: 600; white-space: nowrap; }
2222
.badge-uptodate { background: #064e3b; color: #6ee7b7; }
2323
.badge-outdated { background: #7c2d12; color: #fdba74; }
2424
.badge-partial { background: #713f12; color: #fcd34d; }
@@ -61,7 +61,7 @@
6161
</style>
6262
</head>
6363
<body>
64-
<h1>🐳 <span id="appTitle">Docker Image Watcher</span> <small id="status"></small> <span style="margin-left:auto;display:flex;align-items:center;gap:8px"><a href="#" id="langSwitch" style="color:#64748b;text-decoration:none;font-size:.75rem" onclick="switchLang();return false">IT</a><a href="#" id="logoutLink" style="color:#ef4444;text-decoration:none;font-size:.75rem" onclick="doLogout();return false">Logout</a><label style="font-size:.8rem;font-weight:400;display:flex;align-items:center;gap:6px;cursor:pointer"><span id="hideLabel">Hide up to date</span> <div class="toggle on" id="hideToggle"></div></label></span></h1>
64+
<h1>🐳 <span id="appTitle">Docker Image Watcher</span> <small id="status"></small> <span style="margin-left:auto;display:flex;align-items:center;gap:8px"><button id="updateAllBtn" class="btn btn-group" onclick="doGlobalUpdate()" hidden></button><a href="#" id="langSwitch" style="color:#64748b;text-decoration:none;font-size:.75rem" onclick="switchLang();return false">IT</a><a href="#" id="logoutLink" style="color:#ef4444;text-decoration:none;font-size:.75rem" onclick="doLogout();return false">Logout</a><label style="font-size:.8rem;font-weight:400;display:flex;align-items:center;gap:6px;cursor:pointer"><span id="hideLabel">Hide up to date</span> <div class="toggle on" id="hideToggle"></div></label></span></h1>
6565
<div class="warning-banner" id="rateLimitBanner" hidden>
6666
<div>
6767
<strong id="rateLimitTitle"></strong>
@@ -134,7 +134,7 @@ <h1>🐳 <span id="appTitle">Docker Image Watcher</span> <small id="status"></sm
134134
empty: 'Nessun container in esecuzione',
135135
emptyHint: 'Assicurati che il socket Docker sia montato e che i container siano attivi',
136136
uptodate: '✅ Aggiornato',
137-
outdated: '🔄 Aggiornamento disp.',
137+
outdated: '🔄 Da aggiornare',
138138
partial: '⚠️ Parziale',
139139
unknown: '❓ Sconosciuto',
140140
update: 'Aggiorna',
@@ -180,7 +180,8 @@ <h1>🐳 <span id="appTitle">Docker Image Watcher</span> <small id="status"></sm
180180
}
181181

182182
function renderRateLimit() {
183-
document.getElementById('rateLimitBanner').hidden = !rateLimited || rateLimitDismissed;
183+
const banner = document.getElementById('rateLimitBanner');
184+
banner.style.display = (!rateLimited || rateLimitDismissed) ? 'none' : 'flex';
184185
}
185186

186187
async function checkRateLimit() {
@@ -220,6 +221,10 @@ <h1>🐳 <span id="appTitle">Docker Image Watcher</span> <small id="status"></sm
220221
function render(groups) {
221222
const tbody = document.getElementById('rows');
222223
const counts = { uptodate: 0, outdated: 0, unknown: 0, partial: 0 };
224+
const totalOutdated = groups.reduce((sum, g) => sum + g.containers.filter(c => c.status === 'outdated').length, 0);
225+
const updateAllBtn = document.getElementById('updateAllBtn');
226+
updateAllBtn.hidden = totalOutdated === 0;
227+
updateAllBtn.textContent = t.updateAll(totalOutdated);
223228
let html = '';
224229
if (groups.length === 0) {
225230
html = '<tr><td colspan="5"><div class="empty">' + esc(t.empty) + '<br><p>' + esc(t.emptyHint) + '</p></div></td></tr>';
@@ -238,7 +243,7 @@ <h1>🐳 <span id="appTitle">Docker Image Watcher</span> <small id="status"></sm
238243
<td class="digest">${esc(g.remote_digest)}</td>
239244
<td><span class="badge ${gBadgeClass}">${gBadgeLabel}</span></td>
240245
<td></td>
241-
<td>${outdated > 0 ? `<button class="btn btn-group" data-image="${esc(g.image)}" data-cids="${esc(outdatedCids.join(','))}" onclick="doGroupUpdate(this)">${esc(t.updateAll(total))}</button>` : ''}</td>
246+
<td>${outdated > 0 && total > 1 ? `<button class="btn btn-group" data-image="${esc(g.image)}" data-cids="${esc(outdatedCids.join(','))}" onclick="doGroupUpdate(this)">${esc(t.updateAll(total))}</button>` : ''}</td>
242247
</tr>`;
243248
for (const c of g.containers) {
244249
if (!showAll && c.status === 'uptodate') continue;
@@ -311,6 +316,28 @@ <h1>🐳 <span id="appTitle">Docker Image Watcher</span> <small id="status"></sm
311316
}
312317
}
313318

319+
async function doGlobalUpdate() {
320+
const btn = document.getElementById('updateAllBtn');
321+
btn.disabled = true;
322+
btn.textContent = t.updatingLabel;
323+
try {
324+
const res = await fetch('/api/images');
325+
const groups = await res.json();
326+
for (const g of groups) {
327+
const outdated = g.containers.filter(c => c.status === 'outdated');
328+
if (outdated.length === 0) continue;
329+
await fetch('/api/groups/update', {
330+
method: 'POST',
331+
headers: { 'Content-Type': 'application/json' },
332+
body: JSON.stringify({ image: g.image })
333+
});
334+
}
335+
setTimeout(load, 2000);
336+
} catch(e) {
337+
btn.textContent = t.errorLabel;
338+
}
339+
}
340+
314341
async function pollProgress(cid) {
315342
const cell = document.getElementById('progress-' + cid);
316343
if (!cell) return;

0 commit comments

Comments
 (0)