diff --git a/src/hub/web_ui.py b/src/hub/web_ui.py index ac4b210..703ac3c 100644 --- a/src/hub/web_ui.py +++ b/src/hub/web_ui.py @@ -658,7 +658,7 @@ class WebUIRenderer:
🌐 Server Version & Upstream Release Status
Upstream release tracking via Gitea production channels
- {('UPDATE AVAILABLE' if update_status.get("server_update_available") else 'UP TO DATE')} + {('UPDATE AVAILABLE' if update_status.get("server_update_available") else 'UP TO DATE')}
@@ -667,16 +667,16 @@ class WebUIRenderer:
Latest Upstream Release
-
v{update_status.get('latest_upstream_version') or LOGAR_VERSION}
+
v{update_status.get('latest_upstream_version') or LOGAR_VERSION}
Last Checked
-
{update_status.get('last_checked_utc') or 'Never'}
+
{update_status.get('last_checked_utc') or 'Never'}
- {(f'🌐 View Release on Gitea' if update_status.get("release_url") else '')} + {(f'🌐 View Release on Gitea' if update_status.get("release_url") else '')}
@@ -771,18 +771,18 @@ class WebUIRenderer: WINDOWS {html.escape(hosted_packages.get('windows', {}).get('filename') or 'LOGAR_Client_Setup.exe')} - v{html.escape(str(hosted_packages.get('windows', {}).get('version') or hosted_client_ver))} - {((hosted_packages.get('windows', {}).get('size_bytes', 0) // 1024) if hosted_packages.get('windows', {}).get('exists') else 0)} KB - {(hosted_packages.get('windows', {}).get('sha256', 'N/A')[:16] + '...') if hosted_packages.get('windows', {}).get('sha256') else 'N/A'} - {('Ready' if hosted_packages.get('windows', {}).get('exists') else 'Failed')} + v{html.escape(str(hosted_packages.get('windows', {}).get('version') or hosted_client_ver))} + {((hosted_packages.get('windows', {}).get('size_bytes', 0) // 1024) if hosted_packages.get('windows', {}).get('exists') else 0)} KB + {(hosted_packages.get('windows', {}).get('sha256', 'N/A')[:16] + '...') if hosted_packages.get('windows', {}).get('sha256') else 'N/A'} + {('Ready' if hosted_packages.get('windows', {}).get('exists') else 'Failed')} LINUX {html.escape(hosted_packages.get('linux', {}).get('filename') or 'Linux_Client.bin')} - v{html.escape(str(hosted_packages.get('linux', {}).get('version') or hosted_client_ver))} - {((hosted_packages.get('linux', {}).get('size_bytes', 0) // 1024) if hosted_packages.get('linux', {}).get('exists') else 0)} KB - {(hosted_packages.get('linux', {}).get('sha256', 'N/A')[:16] + '...') if hosted_packages.get('linux', {}).get('sha256') else 'N/A'} - {('Ready' if hosted_packages.get('linux', {}).get('exists') else 'Failed')} + v{html.escape(str(hosted_packages.get('linux', {}).get('version') or hosted_client_ver))} + {((hosted_packages.get('linux', {}).get('size_bytes', 0) // 1024) if hosted_packages.get('linux', {}).get('exists') else 0)} KB + {(hosted_packages.get('linux', {}).get('sha256', 'N/A')[:16] + '...') if hosted_packages.get('linux', {}).get('sha256') else 'N/A'} + {('Ready' if hosted_packages.get('linux', {}).get('exists') else 'Failed')} @@ -1440,9 +1440,19 @@ class WebUIRenderer: if (btn && pane) {{ btn.classList.add('active'); pane.classList.add('active'); + try {{ localStorage.setItem('logar_active_tab', tabId); }} catch(e) {{}} }} }} + window.addEventListener('DOMContentLoaded', () => {{ + try {{ + const savedTab = localStorage.getItem('logar_active_tab'); + if (savedTab && document.getElementById('tabBtn-' + savedTab)) {{ + switchTab(savedTab); + }} + }} catch(e) {{}} + }}); + function showAlert(msg, isSuccess = true) {{ const el = document.getElementById('statusAlert'); el.className = 'alert ' + (isSuccess ? 'alert-success' : 'alert-error'); @@ -1935,17 +1945,71 @@ class WebUIRenderer: el.appendChild(img); }} + function updatePackageTableInPlace(pkgs) {{ + if (!pkgs) return; + if (pkgs.windows) {{ + const w = pkgs.windows; + const vEl = document.getElementById('pkgWinVersion'); + if (vEl && w.version) vEl.textContent = 'v' + w.version; + const szEl = document.getElementById('pkgWinSize'); + if (szEl && w.size_bytes !== undefined) szEl.textContent = Math.floor((w.size_bytes || 0) / 1024) + ' KB'; + const shaEl = document.getElementById('pkgWinSha'); + if (shaEl && w.sha256) {{ shaEl.textContent = w.sha256.substring(0, 16) + '...'; shaEl.title = w.sha256; }} + const stEl = document.getElementById('pkgWinStatus'); + if (stEl) stEl.innerHTML = w.exists ? 'Ready' : 'Failed'; + }} + if (pkgs.linux) {{ + const l = pkgs.linux; + const vEl = document.getElementById('pkgLinuxVersion'); + if (vEl && l.version) vEl.textContent = 'v' + l.version; + const szEl = document.getElementById('pkgLinuxSize'); + if (szEl && l.size_bytes !== undefined) szEl.textContent = Math.floor((l.size_bytes || 0) / 1024) + ' KB'; + const shaEl = document.getElementById('pkgLinuxSha'); + if (shaEl && l.sha256) {{ shaEl.textContent = l.sha256.substring(0, 16) + '...'; shaEl.title = l.sha256; }} + const stEl = document.getElementById('pkgLinuxStatus'); + if (stEl) stEl.innerHTML = l.exists ? 'Ready' : 'Failed'; + }} + }} + async function checkForUpdatesNow() {{ showAlert('Checking upstream repository for new releases...'); try {{ const res = await fetch('/api/server/update/check', {{ method: 'POST' }}); const data = await res.json(); + + const badgeEl = document.getElementById('upstreamReleaseStatusBadge'); + if (badgeEl) {{ + badgeEl.innerHTML = data.server_update_available + ? 'UPDATE AVAILABLE' + : 'UP TO DATE'; + }} + + const verEl = document.getElementById('latestUpstreamVersionText'); + if (verEl && data.latest_upstream_version) {{ + verEl.textContent = 'v' + data.latest_upstream_version; + }} + + const checkEl = document.getElementById('lastCheckedText'); + if (checkEl) {{ + checkEl.textContent = data.last_checked_utc || (new Date().toISOString().replace('T', ' ').substring(0, 19) + ' UTC'); + }} + + const linkEl = document.getElementById('viewReleaseLinkContainer'); + if (linkEl) {{ + linkEl.innerHTML = data.release_url + ? '🌐 View Release on Gitea' + : ''; + }} + + if (data.hosted_packages) {{ + updatePackageTableInPlace(data.hosted_packages); + }} + if (data.server_update_available) {{ showAlert('🔔 Update Available: v' + data.latest_upstream_version + ' is ready!'); }} else {{ - showAlert('✅ LOGAR is up to date (Current: v' + data.current_server_version + ').'); + showAlert('✅ LOGAR is up to date (Current: v' + (data.current_server_version || '0.3.5.2') + ').'); }} - setTimeout(() => location.reload(), 1200); }} catch (err) {{ alert('Failed to check for updates: ' + err.message); }} @@ -1972,7 +2036,6 @@ class WebUIRenderer: const data = await res.json(); if (res.ok && data.status === 'success') {{ showAlert('✅ Fleet update configuration saved successfully!'); - setTimeout(() => location.reload(), 1200); }} else {{ let errMsg = 'Failed to save configuration'; if (typeof data.detail === 'string') errMsg = data.detail; @@ -1992,7 +2055,14 @@ class WebUIRenderer: if (res.ok && data.status === 'success') {{ const dl = (data.results && data.results.downloaded) ? data.results.downloaded.length : 0; showAlert('✅ Upstream synchronization complete (' + dl + ' package(s) downloaded/verified)!'); - setTimeout(() => location.reload(), 1500); + + try {{ + const statusRes = await fetch('/api/server/update/status'); + const statusData = await statusRes.json(); + if (statusData && statusData.hosted_packages) {{ + updatePackageTableInPlace(statusData.hosted_packages); + }} + }} catch(e) {{}} }} else {{ let errMsg = 'Synchronization failed'; if (typeof data.detail === 'string') errMsg = data.detail;