From bc85efe01a95073f6ecb0213e426ffc1d4383805 Mon Sep 17 00:00:00 2001 From: bergeouss Date: Sat, 25 Apr 2026 16:44:13 +0000 Subject: [PATCH] feat: add manual 'Check for Updates' button in System settings (#785) Add a 'Check now' button next to the version badge in the System settings section, allowing users to manually trigger an update check at any time without waiting for the automatic periodic check. Changes: - index.html: add button with spinner and status text inline with version badge - panels.js: add checkUpdatesNow() calling /api/updates/check?force=1 with immediate feedback (checking... / up to date / X updates available) - style.css: style the button block and spinner - i18n.js: add 5 new keys (settings_check_now, settings_checking, settings_up_to_date, settings_updates_available, settings_updates_disabled) in all 6 locales (en, ru, es, de, zh, zh-Hant) --- static/i18n.js | 30 ++++++++++++++++++++++++++++++ static/index.html | 6 +++++- static/panels.js | 36 ++++++++++++++++++++++++++++++++++++ static/style.css | 6 ++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/static/i18n.js b/static/i18n.js index 671afbf6..71cc6878 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -231,6 +231,11 @@ const LOCALES = { settings_section_preferences_meta: 'Defaults and UI behavior for Hermes Web UI.', settings_section_system_title: 'System', settings_section_system_meta: 'Instance version and access controls.', + settings_check_now: 'Check now', + settings_checking: 'Checking\u2026', + settings_up_to_date: 'Up to date \u2713', + settings_updates_available: '{count} update(s) available', + settings_updates_disabled: 'Update checks disabled', settings_dropdown_conversation: 'Conversation', settings_dropdown_appearance: 'Appearance', settings_dropdown_preferences: 'Preferences', @@ -1174,6 +1179,11 @@ const LOCALES = { settings_section_preferences_meta: 'Defaults and UI behavior for Hermes Web UI.', settings_section_preferences_title: 'Preferences', settings_section_system_meta: 'Instance version and access controls.', + settings_check_now: 'Проверить', + settings_checking: 'Проверка\u2026', + settings_up_to_date: 'Актуально \u2713', + settings_updates_available: 'Доступно обновлений: {count}', + settings_updates_disabled: 'Проверка обновлений отключена', settings_section_system_title: 'System', settings_tab_appearance: 'Appearance', settings_tab_conversation: 'Conversation', @@ -1714,6 +1724,11 @@ const LOCALES = { settings_section_preferences_meta: 'Defaults and UI behavior for Hermes Web UI.', settings_section_preferences_title: 'Preferences', settings_section_system_meta: 'Instance version and access controls.', + settings_check_now: 'Comprobar ahora', + settings_checking: 'Comprobando\u2026', + settings_up_to_date: 'Actualizado \u2713', + settings_updates_available: '{count} actualización(es) disponible(s)', + settings_updates_disabled: 'Comprobación de actualizaciones desactivada', settings_section_system_title: 'System', settings_tab_appearance: 'Appearance', settings_tab_conversation: 'Conversation', @@ -2038,6 +2053,11 @@ const LOCALES = { settings_section_preferences_meta: 'Defaults and UI behavior for Hermes Web UI.', settings_section_preferences_title: 'Preferences', settings_section_system_meta: 'Instance version and access controls.', + settings_check_now: 'Jetzt prüfen', + settings_checking: 'Prüfung\u2026', + settings_up_to_date: 'Aktuell \u2713', + settings_updates_available: '{count} Update(s) verfügbar', + settings_updates_disabled: 'Update-Prüfung deaktiviert', settings_section_system_title: 'System', settings_tab_appearance: 'Appearance', settings_tab_conversation: 'Conversation', @@ -2575,6 +2595,11 @@ const LOCALES = { settings_section_preferences_meta: 'Defaults and UI behavior for Hermes Web UI.', settings_section_preferences_title: 'Preferences', settings_section_system_meta: 'Instance version and access controls.', + settings_check_now: '立即检查', + settings_checking: '检查中\u2026', + settings_up_to_date: '已是最新 \u2713', + settings_updates_available: '有 {count} 个更新可用', + settings_updates_disabled: '更新检查已禁用', settings_section_system_title: 'System', settings_tab_appearance: 'Appearance', settings_tab_conversation: 'Conversation', @@ -2742,6 +2767,11 @@ const LOCALES = { settings_section_preferences_meta: 'Hermes Web UI 的預設值與介面行為。', settings_section_system_title: '系統', settings_section_system_meta: '實例版本與存取控制。', + settings_check_now: '立即檢查', + settings_checking: '檢查中\u2026', + settings_up_to_date: '已是最新 \u2713', + settings_updates_available: '有 {count} 個更新可用', + settings_updates_disabled: '更新檢查已禁用', settings_dropdown_conversation: '對話', settings_dropdown_appearance: '外觀', settings_dropdown_preferences: '偏好設定', diff --git a/static/index.html b/static/index.html index 5cd43e22..56ca2f02 100644 --- a/static/index.html +++ b/static/index.html @@ -684,7 +684,11 @@
System
Instance version and access controls.
- +
+ + + +
diff --git a/static/panels.js b/static/panels.js index 980970aa..2600b702 100644 --- a/static/panels.js +++ b/static/panels.js @@ -2507,6 +2507,42 @@ function _applySavedSettingsUi(saved, body, opts){ if(typeof renderSessionList==='function') renderSessionList(); } +async function checkUpdatesNow(){ + const btn=$('btnCheckUpdatesNow'); + const label=$('checkUpdatesLabel'); + const spinner=$('checkUpdatesSpinner'); + const status=$('checkUpdatesStatus'); + if(!btn||!label) return; + // Disable button, show spinner + btn.disabled=true; + if(spinner) spinner.style.display=''; + if(label) label.textContent=t('settings_checking'); + if(status) status.textContent=''; + try { + const data=await api('/api/updates/check?force=1'); + if(data.disabled){ + if(status){status.textContent=t('settings_updates_disabled');status.style.color='var(--muted)';} + } else { + const parts=[]; + if(data.webui&&data.webui.behind>0) parts.push('WebUI: '+data.webui.behind); + if(data.agent&&data.agent.behind>0) parts.push('Agent: '+data.agent.behind); + if(parts.length){ + if(status){status.textContent=t('settings_updates_available').replace('{count}',parts.join(', '));status.style.color='var(--accent)';} + // Also trigger the update banner + if(typeof _showUpdateBanner==='function') _showUpdateBanner(data); + } else { + if(status){status.textContent=t('settings_up_to_date');status.style.color='var(--success)';} + } + } + } catch(e){ + if(status){status.textContent=t('failed_colon')+e.message;status.style.color='var(--error)';} + } finally { + btn.disabled=false; + if(spinner) spinner.style.display='none'; + if(label) label.textContent=t('settings_check_now'); + } +} + async function saveSettings(andClose){ const model=($('settingsModel')||{}).value; const modelChanged=(model||'')!==(_settingsHermesDefaultModelOnOpen||''); diff --git a/static/style.css b/static/style.css index 1cd8f064..e672406c 100644 --- a/static/style.css +++ b/static/style.css @@ -1550,6 +1550,12 @@ main.main.showing-profiles > #mainProfiles{display:flex;} .settings-section-title{font-size:18px;font-weight:600;letter-spacing:-.01em;color:var(--text);line-height:1.3;margin-bottom:4px;} .settings-section-meta{font-size:13px;color:var(--muted);line-height:1.55;} .settings-version-badge{display:inline-flex;align-items:center;padding:3px 8px;border-radius:999px;background:var(--surface);color:var(--muted);font-size:11px;font-weight:600;font-family:'SF Mono',ui-monospace,SFMono-Regular,Menlo,monospace;flex-shrink:0;align-self:flex-start;letter-spacing:.02em;} +#checkUpdatesBlock{display:inline-flex;align-items:center;gap:6px;font-size:12px;flex-shrink:0;align-self:flex-start;} +#checkUpdatesBlock .btn-tiny{padding:4px 10px;border-radius:8px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-size:11px;font-weight:500;cursor:pointer;display:inline-flex;align-items:center;gap:5px;transition:border-color .15s,color .15s;} +#checkUpdatesBlock .btn-tiny:hover{border-color:var(--accent);color:var(--accent);} +#checkUpdatesBlock .btn-tiny:disabled{opacity:.5;cursor:default;} +#checkUpdatesBlock .btn-tiny .spinner-xs{width:12px;height:12px;border:2px solid var(--border);border-top-color:var(--text);border-radius:50%;animation:spin .6s linear infinite;display:none;} +#checkUpdatesStatus{font-size:11px;font-weight:500;white-space:nowrap;} /* Each logical form row is a card surface. Stack with comfortable gap. */ #mainSettings .settings-field{margin-bottom:12px;padding:16px;border:1px solid var(--border);border-radius:12px;background:var(--sidebar);}