|
|
|
|
@ -71,16 +71,12 @@ class LibrePortalSPAClean {
|
|
|
|
|
this.routes.set('/app*', () => this.handleAppDetail());
|
|
|
|
|
this.routes.set('/admin', () => this.handleAdmin()); // Admin area (path-based: /admin/config/<x>, /admin/tools/<x>)
|
|
|
|
|
this.routes.set('/admin*', () => this.handleAdmin());
|
|
|
|
|
this.routes.set('/config', () => this.handleConfigRedirect()); // legacy → /admin
|
|
|
|
|
this.routes.set('/config*', () => this.handleConfigRedirect());
|
|
|
|
|
this.routes.set('/tasks', () => this.handleTasks()); // Handle /tasks without query
|
|
|
|
|
this.routes.set('/tasks*', () => this.handleTasks()); // Handle /tasks with query
|
|
|
|
|
this.routes.set('/backup', () => this.handleBackup());
|
|
|
|
|
this.routes.set('/backup*', () => this.handleBackup());
|
|
|
|
|
this.routes.set('/peers', () => this.handlePeers()); // legacy → /admin/tools/peers
|
|
|
|
|
this.routes.set('/peers*', () => this.handlePeers());
|
|
|
|
|
this.routes.set('/ssh', () => this.handleSsh()); // legacy → /admin/tools/ssh-access
|
|
|
|
|
this.routes.set('/ssh*', () => this.handleSsh());
|
|
|
|
|
// Legacy /config, /peers, /ssh are handled by _legacyRedirect() at the top
|
|
|
|
|
// of navigate() (rewrites to the canonical /admin/* path).
|
|
|
|
|
|
|
|
|
|
//console.log('📍 Routes registered:', Array.from(this.routes.keys()));
|
|
|
|
|
}
|
|
|
|
|
@ -223,7 +219,19 @@ class LibrePortalSPAClean {
|
|
|
|
|
|
|
|
|
|
async navigate(path, addToHistory = true) {
|
|
|
|
|
// console.log('🚀 SPA: navigate called with:', path, 'addToHistory:', addToHistory);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Legacy URL redirects (the old /ssh, /peers, /config short URLs → the Admin
|
|
|
|
|
// area). Rewritten here, at the top of navigate() and BEFORE the isLoading
|
|
|
|
|
// guard, so the canonical /admin/* path is what mounts + shows in the address
|
|
|
|
|
// bar. This replaces the former config-redirect/peers/ssh redirect
|
|
|
|
|
// components (whose handlers re-entered navigate() and were silently no-op'd
|
|
|
|
|
// by the guard below).
|
|
|
|
|
const redirected = this._legacyRedirect(path);
|
|
|
|
|
if (redirected && redirected !== path) {
|
|
|
|
|
path = redirected;
|
|
|
|
|
try { history.replaceState({ route: path }, '', path); } catch (_) {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.isLoading) {
|
|
|
|
|
// console.log('⏳ Navigation already in progress, ignoring:', path);
|
|
|
|
|
return;
|
|
|
|
|
@ -379,14 +387,22 @@ class LibrePortalSPAClean {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async handlePeers() {
|
|
|
|
|
// Legacy /peers → Peers under the Admin area.
|
|
|
|
|
this.navigate('/admin/tools/peers', true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async handleSsh() {
|
|
|
|
|
// Legacy /ssh → SSH Access under the Admin area.
|
|
|
|
|
this.navigate('/admin/tools/ssh-access', true);
|
|
|
|
|
// Map a legacy short URL (/ssh, /peers, /config[?=cat]) to its canonical
|
|
|
|
|
// /admin/* path, or return null if it isn't a legacy redirect. Used at the top
|
|
|
|
|
// of navigate(). Replaces the old config-redirect/peers/ssh handlers.
|
|
|
|
|
_legacyRedirect(path) {
|
|
|
|
|
const full = path || '';
|
|
|
|
|
const p = full.split('?')[0];
|
|
|
|
|
if (p === '/ssh' || p.startsWith('/ssh/')) return '/admin/tools/ssh-access';
|
|
|
|
|
if (p === '/peers' || p.startsWith('/peers/')) return '/admin/tools/peers';
|
|
|
|
|
if (p === '/config' || p.startsWith('/config/') || full.startsWith('/config?')) {
|
|
|
|
|
let cat = 'overview';
|
|
|
|
|
if (full.includes('?=')) cat = full.split('?=')[1] || 'overview';
|
|
|
|
|
else if (full.includes('?')) cat = new URLSearchParams(full.split('?')[1]).get('config') || 'overview';
|
|
|
|
|
else { const seg = p.replace(/^\/config\/?/, ''); if (seg) cat = seg; }
|
|
|
|
|
return (typeof window.adminPath === 'function') ? window.adminPath(cat) : '/admin';
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async handleApps() {
|
|
|
|
|
@ -520,17 +536,6 @@ class LibrePortalSPAClean {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Legacy /config and /config?=<x> → the path-based /admin equivalent.
|
|
|
|
|
async handleConfigRedirect() {
|
|
|
|
|
const search = window.location.search || '';
|
|
|
|
|
let cat = 'overview';
|
|
|
|
|
if (search.includes('?=')) {
|
|
|
|
|
cat = (window.location.pathname + search).split('?=')[1] || 'overview';
|
|
|
|
|
} else {
|
|
|
|
|
cat = new URLSearchParams(search).get('config') || 'overview';
|
|
|
|
|
}
|
|
|
|
|
this.navigate(window.adminPath(cat), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async handleTasks() {
|
|
|
|
|
//console.log('📋 Loading tasks...');
|
|
|
|
|
|
|
|
|
|
|