diff --git a/containers/libreportal/frontend/components/admin/config/js/config-manager.js b/containers/libreportal/frontend/components/admin/config/js/config-manager.js
index ce88a87..b342a0f 100755
--- a/containers/libreportal/frontend/components/admin/config/js/config-manager.js
+++ b/containers/libreportal/frontend/components/admin/config/js/config-manager.js
@@ -72,24 +72,8 @@ if (typeof window.ConfigManager === 'undefined') {
// instances (kind=backup-channel for shared-backup migrate, or
// kind=direct-ssh-direct for live SSH pulls). Same shape as SSH Access:
// we inject its content template, then init PeersPage.
- if (category === 'peers') {
- try { this.sidebar.populateSidebar(); } catch (e) {}
- await lazyLoad('/components/admin/peers/js/peers-page.js');
- try {
- const html = await fetch('/components/admin/peers/html/peers-content.html').then(r => r.text());
- configSection.innerHTML = html;
- } catch (e) {
- configSection.innerHTML = '
Peers page template failed to load.
';
- return;
- }
- if (typeof PeersPage !== 'undefined') {
- window.peersPage = new PeersPage('config-section');
- await window.peersPage.init();
- } else {
- configSection.innerHTML = 'PeersPage controller not loaded.
';
- }
- return;
- }
+ // Peers moved out of Admin → Overview › Migrate › Peers; /admin/tools/peers
+ // redirects there, so this branch is intentionally gone.
// System is an admin tool page that internally routes between index /
// metric / per-app / storage sub-views based on the URL sub-path.
diff --git a/containers/libreportal/frontend/components/admin/peers/js/peers-page.js b/containers/libreportal/frontend/components/admin/peers/js/peers-page.js
index 6e96106..3bd8545 100644
--- a/containers/libreportal/frontend/components/admin/peers/js/peers-page.js
+++ b/containers/libreportal/frontend/components/admin/peers/js/peers-page.js
@@ -431,7 +431,7 @@ class PeersPage {
}
notify(message, kind) {
- if (typeof window.showNotification === 'function') window.showNotification(message, kind);
+ if (window.notificationSystem && window.notificationSystem.show) window.notificationSystem.show(message, kind || 'info');
else if (kind === 'error') console.error(message);
else console.log(message);
}
diff --git a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js
index 7c938fb..d87c4d3 100644
--- a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js
+++ b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js
@@ -428,17 +428,26 @@ class OverviewManager {
// configuration sections (its sidebar restyled as a nested tab strip). On a
// revisit we refresh rather than re-mount, to keep its sub-tab + expand state.
mountBackupCenter(pane) {
+ // Honor an optional sub-tab deep-link (/overview/backups/), e.g. the
+ // Restore empty-state's "Open Locations" button.
+ const seg = window.location.pathname.replace(/^\/overview\/backups\/?/, '').split('/')[0];
+ const sub = ['dashboard', 'backups', 'locations', 'configuration'].includes(seg) ? seg : null;
// Detect a prior mount by the embedded fragment in THIS pane — not by
// #backup-section, which the per-app Backups tab also defines.
if (pane.querySelector('.backup-layout') && window.overviewBackupPage) {
- try { window.overviewBackupPage.refreshAll().then(() => window.overviewBackupPage.render()).catch(() => {}); } catch (_) {}
+ try {
+ window.overviewBackupPage.refreshAll().then(() => {
+ window.overviewBackupPage.render();
+ if (sub) window.overviewBackupPage.switchTab(sub);
+ }).catch(() => {});
+ } catch (_) {}
return;
}
pane.innerHTML = 'Loading backup center…
';
- this._loadBackupCenter(pane);
+ this._loadBackupCenter(pane, sub);
}
- async _loadBackupCenter(pane) {
+ async _loadBackupCenter(pane, sub) {
if (this._backupLoading) return;
this._backupLoading = true;
try {
@@ -456,6 +465,7 @@ class OverviewManager {
try { if (window.overviewBackupPage) window.overviewBackupPage.dispose(); } catch (_) {}
window.overviewBackupPage = new BackupPage({ embedded: true });
await window.overviewBackupPage.init();
+ if (sub) { try { window.overviewBackupPage.switchTab(sub); } catch (_) {} }
} catch (_) {
pane.innerHTML = 'Failed to load the backup center.
';
} finally {
diff --git a/containers/libreportal/frontend/components/apps/overview/migrate/js/migrate-page.js b/containers/libreportal/frontend/components/apps/overview/migrate/js/migrate-page.js
index 5d2804b..fd40b80 100644
--- a/containers/libreportal/frontend/components/apps/overview/migrate/js/migrate-page.js
+++ b/containers/libreportal/frontend/components/apps/overview/migrate/js/migrate-page.js
@@ -68,7 +68,7 @@ class MigratePage {
}
const locBtn = e.target.closest('[data-action="go-to-locations"]');
if (locBtn && this.root()?.contains(locBtn)) {
- if (window.navigateToRoute) window.navigateToRoute('/overview/backups');
+ if (window.navigateToRoute) window.navigateToRoute('/overview/backups/locations');
return;
}
if (e.target.closest('#ov-migrate-confirm')) { this.confirmMigrate(); return; }
@@ -107,8 +107,9 @@ class MigratePage {
closeModal() { document.getElementById('ov-migrate-modal')?.classList.remove('open'); }
notify(msg, type) {
- const n = (window.LP && window.LP.services && window.LP.services.notify) || window.notify;
- if (n && n.show) n.show(msg, type || 'info');
+ if (window.notificationSystem && window.notificationSystem.show) window.notificationSystem.show(msg, type || 'info');
+ else if (type === 'error') console.error(msg);
+ else console.log(msg);
}
async runTask(command, type, app) {
diff --git a/containers/libreportal/frontend/components/backup/core/js/backup-fetch-client.js b/containers/libreportal/frontend/components/backup/core/js/backup-fetch-client.js
index f27c56b..b13c01f 100644
--- a/containers/libreportal/frontend/components/backup/core/js/backup-fetch-client.js
+++ b/containers/libreportal/frontend/components/backup/core/js/backup-fetch-client.js
@@ -2,26 +2,17 @@
Object.assign(BackupPage.prototype, {
async refreshAll() {
const ts = Date.now();
- const [dashboard, locations, , schema, migrate, peersData] = await Promise.all([
+ const [dashboard, locations, , schema] = await Promise.all([
this.fetchJson(`/data/backup/generated/dashboard.json?t=${ts}`),
this.fetchJson(`/data/backup/generated/locations.json?t=${ts}`),
this.loadSystemConfigs(),
- this.fetchJson(`/data/backup/generated/schema.json?t=${ts}`),
- this.fetchJson(`/data/backup/generated/migrate.json?t=${ts}`),
- this.fetchJson(`/data/peers/generated/peers.json?t=${ts}`)
+ this.fetchJson(`/data/backup/generated/schema.json?t=${ts}`)
]);
this.dashboard = dashboard;
this.locations = locations;
this.locSchema = schema;
- this.migrate = migrate;
- // Build hostname → friendly-name lookup once so renderMigrate can show
- // "homelab (host: homelab.lan)" instead of bare hostnames.
- this.hostnameToPeerName = {};
- for (const p of (peersData?.peers || [])) {
- if (p.kind === 'backup-channel' && p.config?.hostname) {
- this.hostnameToPeerName[p.config.hostname] = p.name;
- }
- }
+ // (migrate.json + peers lookup moved to MigratePage when Migrate left the
+ // backup center — nothing here consumes them anymore.)
this.snapshotsByLoc = {};
if (!this.engines.length) await this.loadEngines();