fix(webui): reload app/service data after a config apply

config_update re-deploys apps (ports, subdomains, Open URLs, routing) but the
WebUI only unlocked the nav on completion — leaving stale URLs/routing until a
manual reload. apps-manager now refreshes apps + services and repaints the
current view when a config_update task completes, via a reusable
refreshAppsAndView() helper (also the basis for the upcoming task-refresh
registry).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
librelad 2026-05-28 21:52:29 +01:00
parent 6010727391
commit 7f034d3e02

View File

@ -65,6 +65,14 @@ class AppsManager {
return;
}
// Config apply re-deploys apps (ports/subdomains/URLs/routing). Reload
// app + service data and repaint so the UI reflects the new config
// instead of showing stale URLs/routing until a manual refresh.
if (action === 'config_update' && status === 'completed') {
await this.refreshAppsAndView();
return;
}
// First-install welcome modal — only on the very first successful install per app per browser.
if (action === 'install' && status === 'completed' && appName) {
const key = `libreportal.welcomeShown.${String(appName).toLowerCase()}`;
@ -181,6 +189,33 @@ class AppsManager {
}
}
// Reload apps + service data and repaint whatever app surface is on screen
// (grid or detail), with no manual page reload. Used after any task that
// changes app config/state — config_update, restore, start/stop/restart,
// update, rebuild — so the UI reflects the result.
async refreshAppsAndView(appName) {
this.clearCache();
await this.reloadAppsData();
if (window.serviceButtons) {
try { await window.serviceButtons.loadServices(); } catch (e) { console.error('loadServices failed:', e); }
}
const url = new URL(window.location.href);
const pathname = window.location.pathname;
const currentApp = decodeURIComponent((pathname.match(/^\/app\/([^/?]+)/) || [])[1] || '')
|| url.searchParams.get('app') || url.searchParams.get('') || '';
const isAppsPage = pathname === '/apps' || pathname.startsWith('/apps/');
const isAppDetailPage = pathname === '/app' || pathname.startsWith('/app/');
if (isAppsPage && !isAppDetailPage) {
this.renderApps(window.appsCategory || 'all');
} else if (isAppDetailPage && currentApp && (!appName || currentApp === appName)) {
setTimeout(() => {
this.renderAppDetail(currentApp, null, true, { skipReload: true })
.catch(err => console.error('renderAppDetail failed:', err));
}, 0);
}
if (typeof window.renderInstalledApps === 'function') window.renderInstalledApps();
}
async loadApps(category = 'all') {
// Check cache first
if (this.cache.has(category)) {