138 lines
4.9 KiB
JavaScript
138 lines
4.9 KiB
JavaScript
// ========== CARD HEALTH & UPDATE BADGES ==========
|
|
(function() {
|
|
// Fetch health data and update card UI
|
|
async function refreshCardHealth() {
|
|
try {
|
|
const res = await fetch('/api/v1/health-checks/status');
|
|
const data = await res.json();
|
|
if (!data.success || !data.status) return;
|
|
|
|
for (const [serviceId, svc] of Object.entries(data.status)) {
|
|
const uptimeEl = document.getElementById('uptime-' + serviceId);
|
|
const barEl = document.getElementById('uptime-bar-' + serviceId);
|
|
if (!uptimeEl) continue;
|
|
|
|
const uptime24 = svc.uptime?.['24h'];
|
|
if (uptime24 !== undefined && uptime24 !== null) {
|
|
const pct = uptime24.toFixed(1);
|
|
uptimeEl.textContent = `${pct}% uptime`;
|
|
// Color class
|
|
uptimeEl.className = 'uptime-chip';
|
|
if (uptime24 >= 99.9) uptimeEl.classList.add('excellent');
|
|
else if (uptime24 >= 99) uptimeEl.classList.add('good');
|
|
else if (uptime24 >= 95) uptimeEl.classList.add('degraded');
|
|
else uptimeEl.classList.add('poor');
|
|
|
|
if (barEl) barEl.style.width = pct + '%';
|
|
}
|
|
}
|
|
} catch (_) {
|
|
/* Health check API unavailable — uptime chips stay hidden */
|
|
console.warn('[Card Badges] Health check API unavailable');
|
|
}
|
|
}
|
|
|
|
// Track dismissed updates (per session)
|
|
let dismissedUpdates;
|
|
try {
|
|
dismissedUpdates = new Set(JSON.parse(safeSessionGet('dismissed-updates') || '[]'));
|
|
} catch (_) {
|
|
/* Session storage unavailable */
|
|
dismissedUpdates = new Set();
|
|
}
|
|
|
|
// Track global update state for cross-component access
|
|
let knownUpdates = [];
|
|
|
|
// Fetch update data and show badges
|
|
async function refreshCardUpdates(notifyNew) {
|
|
try {
|
|
const res = await fetch('/api/v1/updates/available');
|
|
const data = await res.json();
|
|
if (!data.success) return;
|
|
|
|
// Clear all update badges first
|
|
document.querySelectorAll('.update-available-badge').forEach(el => el.classList.remove('visible'));
|
|
|
|
const updates = data.updates || [];
|
|
knownUpdates = updates; // store globally
|
|
|
|
// Notify if new updates appeared (periodic check with notification)
|
|
if (notifyNew && updates.length > 0) {
|
|
const prev = window._lastKnownUpdateCount || 0;
|
|
if (prev > 0 && updates.length > prev) {
|
|
showNotification(`${updates.length} container update(s) available — click Update Management to review.`, 'info');
|
|
}
|
|
window._lastKnownUpdateCount = updates.length;
|
|
}
|
|
|
|
if (!updates.length) return;
|
|
|
|
for (const upd of updates) {
|
|
// Try to match by container name to service id
|
|
const apps = window.APPS || [];
|
|
for (const app of apps) {
|
|
if (app.containerId === upd.containerId || app.id === upd.containerName || app.name === upd.containerName) {
|
|
// Skip dismissed updates
|
|
if (dismissedUpdates.has(app.id)) break;
|
|
const badge = document.getElementById('update-badge-' + app.id);
|
|
const updateBtn = document.getElementById('update-btn-' + app.id);
|
|
if (badge) {
|
|
badge.classList.add('visible');
|
|
badge.title = `Update available — click to open Update Management.`;
|
|
badge.style.cursor = 'pointer';
|
|
badge.onclick = (e) => {
|
|
e.stopPropagation();
|
|
// Open Update Management modal focused on this app
|
|
if (window.openUpdateModal) window.openUpdateModal(app.id);
|
|
};
|
|
}
|
|
// Highlight update button if update is available
|
|
if (updateBtn) {
|
|
updateBtn.style.background = '#f97316';
|
|
updateBtn.style.borderColor = '#f97316';
|
|
updateBtn.style.boxShadow = '0 0 6px #f9731688';
|
|
updateBtn.title = `Update available — click to open Update Management.`;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch (_) {
|
|
/* Updates API unavailable — badges stay hidden */
|
|
console.warn('[Card Badges] Updates API unavailable');
|
|
}
|
|
}
|
|
|
|
// Run health and update checks after main refresh, and periodically
|
|
function scheduleCardEnhancements() {
|
|
// Initial load (delayed to not compete with main probe checks)
|
|
setTimeout(() => {
|
|
refreshCardHealth();
|
|
refreshCardUpdates();
|
|
}, 5000);
|
|
|
|
// Periodic refresh every 60 seconds — notify on new updates detected
|
|
setInterval(() => {
|
|
refreshCardHealth();
|
|
refreshCardUpdates(true); // true = notify if new updates found
|
|
}, 60000);
|
|
}
|
|
|
|
// Hook into main refresh cycle
|
|
const origRefreshAll = window.refreshAll;
|
|
if (origRefreshAll) {
|
|
window.refreshAll = async function() {
|
|
try {
|
|
await origRefreshAll();
|
|
// Refresh health data after main status check
|
|
setTimeout(refreshCardHealth, 1000);
|
|
} catch (e) {
|
|
console.warn('[Card Badges] Error in refreshAll hook:', e.message);
|
|
}
|
|
};
|
|
}
|
|
|
|
scheduleCardEnhancements();
|
|
})();
|