cron und module

This commit is contained in:
2026-03-08 02:31:08 +01:00
parent 0b53d7756e
commit f52bb684ce
5 changed files with 466 additions and 2 deletions

View File

@@ -17,6 +17,7 @@
const modalTitle = document.querySelector('[data-host-modal-title]');
const closeBtn = document.querySelector('[data-host-close]');
const newBtn = document.querySelector('[data-host-new]');
const checkAllBtn = document.querySelector('[data-host-check-all]');
const unsavedBar = document.querySelector('[data-host-unsaved]');
const discardBtn = document.querySelector('[data-host-discard]');
@@ -148,4 +149,128 @@
document.querySelectorAll('.host-card').forEach((card) => {
fetchStatus(card);
});
const setUpdateUi = (card, data) => {
const upd = card.querySelector('[data-update-badge]');
const upg = card.querySelector('[data-upgrade-badge]');
const time = card.querySelector('[data-update-time]');
if (upd) {
if (data.updates && typeof data.updates.count === 'number') {
upd.textContent = `Updates: ${data.updates.count}`;
upd.classList.toggle('badge-warn', data.updates.count > 0);
upd.classList.toggle('badge-ok', data.updates.count === 0);
if (data.updates.preview) {
upd.setAttribute('title', data.updates.preview);
}
} else {
upd.textContent = 'Updates: Fehler';
upd.classList.add('badge-error');
if (data.updates && data.updates.error) {
upd.setAttribute('title', data.updates.error);
}
}
}
if (upg) {
if (data.os && typeof data.os.available === 'boolean') {
upg.textContent = data.os.available ? 'OS: Upgrade verfügbar' : 'OS: OK';
upg.classList.toggle('badge-warn', data.os.available);
upg.classList.toggle('badge-ok', !data.os.available);
if (data.os.raw) upg.setAttribute('title', data.os.raw);
} else {
upg.textContent = 'OS: Fehler';
upg.classList.add('badge-error');
if (data.os && data.os.error) {
upg.setAttribute('title', data.os.error);
}
}
}
if (time && data.checked_at) {
const dt = new Date(data.checked_at);
time.textContent = isNaN(dt.getTime()) ? data.checked_at : dt.toLocaleString();
}
};
const checkHostUpdates = (card) => {
const id = card.dataset.hostId;
if (!id) return Promise.resolve();
const btn = card.querySelector('[data-host-check]');
if (btn) {
btn.disabled = true;
btn.textContent = 'Prüfe...';
}
return fetch(`${window.location.pathname}?update_json=1&id=${encodeURIComponent(id)}`, { cache: 'no-store' })
.then((res) => res.json())
.then((data) => {
if (data && data.ok) {
setUpdateUi(card, data);
}
})
.finally(() => {
if (btn) {
btn.disabled = false;
btn.textContent = 'Updates prüfen';
}
});
};
document.querySelectorAll('[data-host-check]').forEach((btn) => {
btn.addEventListener('click', () => {
const card = btn.closest('.host-card');
if (card) checkHostUpdates(card);
});
});
if (checkAllBtn) {
checkAllBtn.addEventListener('click', async () => {
const cards = Array.from(document.querySelectorAll('.host-card'));
for (const card of cards) {
await checkHostUpdates(card);
}
});
}
const applyStoredUpdate = (card) => {
const checkedAt = card.dataset.updateChecked || '';
const updateCount = card.dataset.updateCount;
const updateError = card.dataset.updateError || '';
const upgradeAvailable = card.dataset.upgradeAvailable;
const upgradeRaw = card.dataset.upgradeRaw || '';
const upgradeError = card.dataset.upgradeError || '';
const payload = {
updates: {},
os: {},
checked_at: checkedAt || '',
};
if (updateError) {
payload.updates.error = updateError;
} else if (updateCount !== undefined && updateCount !== '') {
payload.updates.count = Number(updateCount);
payload.updates.preview = '';
}
if (upgradeError) {
payload.os.error = upgradeError;
} else if (upgradeAvailable !== undefined && upgradeAvailable !== '') {
payload.os.available = upgradeAvailable === '1' || upgradeAvailable === 'true';
payload.os.raw = upgradeRaw;
}
setUpdateUi(card, payload);
};
const isStale = (checkedAt) => {
if (!checkedAt) return true;
const dt = new Date(checkedAt);
if (isNaN(dt.getTime())) return true;
const ageMs = Date.now() - dt.getTime();
return ageMs > 24 * 60 * 60 * 1000;
};
document.querySelectorAll('.host-card').forEach((card) => {
applyStoredUpdate(card);
if (isStale(card.dataset.updateChecked || '')) {
checkHostUpdates(card);
}
});
})();

View File

@@ -126,6 +126,35 @@
.status-auth { background: #fbbf24; }
.status-down { background: #ef4444; }
.host-update-row {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.update-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 999px;
border: 1px solid var(--line);
background: var(--panel-2);
font-size: 0.75rem;
font-weight: 600;
}
.badge-ok {
border-color: rgba(49,196,141,0.5);
background: rgba(49,196,141,0.15);
}
.badge-warn {
border-color: rgba(251,191,36,0.6);
background: rgba(251,191,36,0.2);
}
.badge-error {
border-color: rgba(239,68,68,0.6);
background: rgba(239,68,68,0.15);
}
.action-menu {
position: relative;
}