Merge claude/1
This commit is contained in:
commit
7e7a7f524c
@ -97,15 +97,15 @@ class AppTabbedManager {
|
||||
|
||||
// Get app name from URL parameter
|
||||
getAppFromURL() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let appName = urlParams.get('app');
|
||||
// Path-based /app/<name> first, then legacy ?app= / ?=name.
|
||||
let appName = window.location.pathname.replace(/^\/app\/?/, '').split('/')[0];
|
||||
appName = appName ? decodeURIComponent(appName) : '';
|
||||
|
||||
// Fallback to old format if app param not found
|
||||
if (!appName) {
|
||||
const fullPath = window.location.search;
|
||||
if (fullPath.includes('?=')) {
|
||||
const [basePath, query] = fullPath.split('?=');
|
||||
appName = query.split('&')[0]; // Get only the app name, ignore other params
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
appName = urlParams.get('app');
|
||||
if (!appName && window.location.search.includes('?=')) {
|
||||
appName = window.location.search.split('?=')[1].split('&')[0];
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,88 +163,34 @@ class AppTabbedManager {
|
||||
search.includes('?=')); // Old format app pages
|
||||
}
|
||||
|
||||
// Update URL with app and tab
|
||||
// Update URL with app and tab — path-based: /app/<app>?tab=<tab>&task=<task>.
|
||||
updateURL(app = null, tab = null) {
|
||||
// console.log('🔍 updateURL called with:', { app, tab });
|
||||
// console.log('🔍 Current URL before update:', window.location.href);
|
||||
// Only update URLs on app pages - prevent interference with other pages.
|
||||
if (!this.isAppPage()) return;
|
||||
|
||||
// Only update URLs on app pages - prevent interference with other pages
|
||||
if (!this.isAppPage()) {
|
||||
// console.log('🚫 Not on app page, skipping URL update');
|
||||
return;
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const fromPath = window.location.pathname.replace(/^\/app\/?/, '').split('/')[0];
|
||||
const currentApp = app || (fromPath ? decodeURIComponent(fromPath) : '') || this.currentApp;
|
||||
if (!currentApp) return;
|
||||
|
||||
const q = new URLSearchParams();
|
||||
const finalTab = tab || params.get('tab');
|
||||
if (finalTab) q.set('tab', finalTab);
|
||||
// Keep a deep-linked task only when staying on the same app (tab-only update).
|
||||
if (!app) {
|
||||
const task = params.get('task');
|
||||
if (task) q.set('task', task);
|
||||
}
|
||||
|
||||
const url = new URL(window.location);
|
||||
const params = new URLSearchParams(url.search);
|
||||
const fullPath = window.location.search; // Define here for both blocks
|
||||
|
||||
// Handle both old format (?=appname) and new format (?app=appname)
|
||||
if (app) {
|
||||
// Check if we're using the old format
|
||||
if (fullPath.includes('?=')) {
|
||||
// Update old format: /app?=appname&tab=tabname
|
||||
const newURL = `/app?=${app}`;
|
||||
if (tab) {
|
||||
// console.log('🔄 Updating URL to:', `${newURL}&tab=${tab}`);
|
||||
window.history.replaceState({}, '', `${newURL}&tab=${tab}`);
|
||||
} else {
|
||||
// console.log('🔄 Updating URL to:', newURL);
|
||||
window.history.replaceState({}, '', newURL);
|
||||
}
|
||||
} else {
|
||||
// Update new format: /app?app=appname&tab=tabname
|
||||
if (tab) {
|
||||
params.set('app', app);
|
||||
params.set('tab', tab);
|
||||
} else {
|
||||
params.set('app', app);
|
||||
}
|
||||
const newSearch = params.toString();
|
||||
// console.log('🔄 Updating URL to:', `${window.location.pathname}?${newSearch}`);
|
||||
window.history.replaceState({}, '', `${window.location.pathname}?${newSearch}`);
|
||||
}
|
||||
} else {
|
||||
// Only updating tab, preserve existing app and task parameters
|
||||
if (fullPath.includes('?=')) {
|
||||
// Old format: preserve app and task, update tab
|
||||
const currentApp = params.get('=') || this.currentApp;
|
||||
const currentTask = params.get('task');
|
||||
let newURL = `/app?=${currentApp}&tab=${tab}`;
|
||||
if (currentTask) {
|
||||
newURL += `&task=${currentTask}`;
|
||||
}
|
||||
// console.log('🔄 Updating URL (old format) to:', newURL);
|
||||
window.history.replaceState({}, '', newURL);
|
||||
} else {
|
||||
// New format: preserve app and task, update tab
|
||||
const currentApp = params.get('app') || this.currentApp;
|
||||
const currentTask = params.get('task');
|
||||
params.set('app', currentApp);
|
||||
params.set('tab', tab);
|
||||
if (currentTask) {
|
||||
params.set('task', currentTask);
|
||||
}
|
||||
const newSearch = params.toString();
|
||||
// console.log('🔄 Updating URL (new format) to:', `${window.location.pathname}?${newSearch}`);
|
||||
window.history.replaceState({}, '', `${window.location.pathname}?${newSearch}`);
|
||||
}
|
||||
}
|
||||
const qs = q.toString();
|
||||
window.history.replaceState({}, '', `/app/${encodeURIComponent(currentApp)}${qs ? '?' + qs : ''}`);
|
||||
}
|
||||
|
||||
// Update current app and refresh content
|
||||
updateApp(newAppName) {
|
||||
this.setCurrentApp(newAppName);
|
||||
|
||||
// Reset URL to config tab
|
||||
const currentUrl = window.location.href;
|
||||
let newUrl;
|
||||
if (currentUrl.includes('tab=')) {
|
||||
newUrl = currentUrl.replace(/tab=[^&]*/, 'tab=config');
|
||||
} else {
|
||||
newUrl = `${currentUrl}&tab=config`;
|
||||
}
|
||||
history.replaceState({}, '', newUrl);
|
||||
|
||||
// Reset to the config tab on the path-based app URL.
|
||||
history.replaceState({}, '', `/app/${encodeURIComponent(newAppName)}?tab=config`);
|
||||
this.switchTab('config');
|
||||
}
|
||||
|
||||
@ -593,7 +539,7 @@ class AppTabbedManager {
|
||||
const currentApp = this.currentApp || '';
|
||||
|
||||
// Construct proper URL with correct parameter order
|
||||
const newUrl = `/app?=${currentApp}&tab=tasks&task=${taskId}`;
|
||||
const newUrl = `/app/${currentApp}?tab=tasks&task=${taskId}`;
|
||||
// console.log('🔍 Updating URL with task parameter:', newUrl);
|
||||
history.pushState({}, '', newUrl);
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ class AppsManager {
|
||||
// reset password) show without needing a page refresh. Don't
|
||||
// switch tabs — they may be reading the tool's task log.
|
||||
const url = new URL(window.location.href);
|
||||
const currentAppFromUrl = url.searchParams.get('app') || url.searchParams.get('');
|
||||
const currentAppFromUrl = decodeURIComponent((window.location.pathname.match(/^\/app\/([^/?]+)/) || [])[1] || '') || url.searchParams.get('app') || url.searchParams.get('');
|
||||
const onAppDetail = window.location.pathname === '/app' || window.location.pathname.startsWith('/app/');
|
||||
if (onAppDetail && appName && currentAppFromUrl === appName) {
|
||||
this.displayConfigForm?.((window.apps || []).find(a =>
|
||||
@ -115,7 +115,7 @@ class AppsManager {
|
||||
}
|
||||
|
||||
const currentUrl = new URL(window.location.href);
|
||||
const currentAppFromUrl = currentUrl.searchParams.get('app') || currentUrl.searchParams.get('');
|
||||
const currentAppFromUrl = decodeURIComponent((window.location.pathname.match(/^\/app\/([^/?]+)/) || [])[1] || '') || currentUrl.searchParams.get('app') || currentUrl.searchParams.get('');
|
||||
const pathname = window.location.pathname;
|
||||
const isAppsPage = pathname === '/apps' || pathname.startsWith('/apps/');
|
||||
const isAppDetailPage = pathname === '/app' || pathname.startsWith('/app/');
|
||||
@ -251,7 +251,7 @@ class AppsManager {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
if (path === '/app' || path.startsWith('/app/') || searchParams.has('app')) {
|
||||
const appName = searchParams.get('app') || window.appName || '';
|
||||
const appName = decodeURIComponent((path.match(/^\/app\/([^/?]+)/) || [])[1] || '') || searchParams.get('app') || window.appName || '';
|
||||
this.showAppDetail(appName);
|
||||
} else {
|
||||
// Use the category parsed by SPA
|
||||
@ -266,7 +266,7 @@ class AppsManager {
|
||||
|
||||
// Update URL only for specific categories, not for 'all'
|
||||
if (category && category !== 'all') {
|
||||
history.pushState({}, '', `/apps?=${category}`);
|
||||
history.pushState({}, '', `/apps/${category}`);
|
||||
}
|
||||
// For 'all' category, keep URL as /apps to avoid redirect loops
|
||||
|
||||
@ -311,7 +311,7 @@ class AppsManager {
|
||||
// console.log('🔍 Preserving existing tab:', targetTab);
|
||||
}
|
||||
|
||||
const newUrl = `/app?=${appName}&tab=${targetTab}`;
|
||||
const newUrl = `/app/${appName}?tab=${targetTab}`;
|
||||
// console.log('🔍 Setting URL to:', newUrl);
|
||||
history.pushState({}, '', newUrl);
|
||||
|
||||
@ -369,7 +369,7 @@ class AppsManager {
|
||||
}
|
||||
|
||||
// Set URL to target tab (config or tasks)
|
||||
const newUrl = `/app?=${appName}&tab=${targetTab}`;
|
||||
const newUrl = `/app/${appName}?tab=${targetTab}`;
|
||||
history.pushState({}, '', newUrl);
|
||||
|
||||
// Update app-tabbed-manager. setCurrentApp clears stale disable state from
|
||||
@ -509,7 +509,7 @@ class AppsManager {
|
||||
if (categoryId === 'all') {
|
||||
history.pushState({}, '', '/apps');
|
||||
} else {
|
||||
history.pushState({}, '', `/apps?=${categoryId}`);
|
||||
history.pushState({}, '', `/apps/${categoryId}`);
|
||||
}
|
||||
|
||||
// Direct view update without URL change to avoid conflicts
|
||||
@ -2086,9 +2086,9 @@ class AppsManager {
|
||||
|
||||
navigateToServiceApp(slug) {
|
||||
if (typeof window.navigateToApp === 'function') return window.navigateToApp(slug);
|
||||
if (window.librePortalSPA?.navigate) return window.librePortalSPA.navigate(`/app?=${slug}`);
|
||||
if (typeof window.navigateToRoute === 'function') return window.navigateToRoute(`app?=${slug}`);
|
||||
window.location.href = `/app?=${slug}`;
|
||||
if (window.librePortalSPA?.navigate) return window.librePortalSPA.navigate(`/app/${slug}`);
|
||||
if (typeof window.navigateToRoute === 'function') return window.navigateToRoute(`app/${slug}`);
|
||||
window.location.href = `/app/${slug}`;
|
||||
}
|
||||
|
||||
// Find matching CFG_ key for a field (working method from app-config-original.js)
|
||||
@ -3221,10 +3221,10 @@ class AppsManager {
|
||||
}, 500);
|
||||
} else if (window.librePortalSPA) {
|
||||
// Fallback: navigate to app with tasks tab
|
||||
const taskUrl = task ? `/app?=${appName}&tab=tasks&task=${task.id}` : `/app?=${appName}&tab=tasks`;
|
||||
const taskUrl = task ? `/app/${appName}?tab=tasks&task=${task.id}` : `/app/${appName}?tab=tasks`;
|
||||
window.librePortalSPA.navigateTo(taskUrl);
|
||||
} else if (window.navigateToRoute) {
|
||||
window.navigateToRoute(`app?=${appName}&tab=tasks${task ? `&task=${task.id}` : ''}`);
|
||||
window.navigateToRoute(`app/${appName}?tab=tasks${task ? `&task=${task.id}` : ''}`);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
@ -3466,11 +3466,11 @@ class AppsManager {
|
||||
}, 500);
|
||||
} else if (window.librePortalSPA) {
|
||||
// Fallback: navigate to app with tasks tab
|
||||
const taskUrl = task ? `/app?=${appName}&tab=tasks&task=${task.id}` : `/app?=${appName}&tab=tasks`;
|
||||
const taskUrl = task ? `/app/${appName}?tab=tasks&task=${task.id}` : `/app/${appName}?tab=tasks`;
|
||||
// console.log(`🔄 Navigating to app tasks with uninstall task: ${task?.id}`);
|
||||
window.librePortalSPA.navigateTo(taskUrl);
|
||||
} else if (window.navigateToRoute) {
|
||||
window.navigateToRoute(`app?=${appName}&tab=tasks${task ? `&task=${task.id}` : ''}`);
|
||||
window.navigateToRoute(`app/${appName}?tab=tasks${task ? `&task=${task.id}` : ''}`);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
|
||||
@ -117,6 +117,10 @@ class BackupPage {
|
||||
either source resolve correctly. */
|
||||
parseTabFromUrl() {
|
||||
const allowed = new Set(['dashboard', 'backups', 'locations', 'configuration']);
|
||||
// Path-based: /backup/<tab> (bare /backup → default tab).
|
||||
const seg = window.location.pathname.replace(/^\/backup\/?/, '').split('/')[0];
|
||||
if (seg && allowed.has(seg)) return seg;
|
||||
// Legacy ?=<tab> / ?backup=<tab> / ?tab=<tab> for old links.
|
||||
const search = window.location.search || '';
|
||||
const legacy = search.match(/\?=([^&]+)/);
|
||||
if (legacy && allowed.has(legacy[1])) return legacy[1];
|
||||
@ -376,7 +380,7 @@ class BackupPage {
|
||||
}
|
||||
|
||||
pushTabToUrl(tab) {
|
||||
const url = `/backup?=${tab}`;
|
||||
const url = `/backup/${tab}`;
|
||||
// Use replaceState for the *first* push (initial tab inferred from
|
||||
// URL); otherwise pushState so back/forward navigates between tabs.
|
||||
if (!this._pushedAnyTab) {
|
||||
|
||||
@ -82,9 +82,9 @@ class ConfigForm {
|
||||
);
|
||||
|
||||
if (task && window.librePortalSPA && typeof window.librePortalSPA.navigate === 'function') {
|
||||
setTimeout(() => window.librePortalSPA.navigate(`/tasks?=all&task=${task.id}`), 400);
|
||||
setTimeout(() => window.librePortalSPA.navigate(`/tasks/all?task=${task.id}`), 400);
|
||||
} else if (task && window.navigateToRoute) {
|
||||
setTimeout(() => window.navigateToRoute(`tasks?=all&task=${task.id}`), 400);
|
||||
setTimeout(() => window.navigateToRoute(`tasks/all?task=${task.id}`), 400);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('ConfigForm: Error saving configuration:', error);
|
||||
|
||||
@ -39,7 +39,7 @@ function createInstalledAppCard(app) {
|
||||
const shortName = app.name.split(' - ')[0].trim();
|
||||
|
||||
return `
|
||||
<div class="frontpage-app-tile" onclick="window.location.href='/app?=${appName}'">
|
||||
<div class="frontpage-app-tile" onclick="window.location.href='/app/${appName}'">
|
||||
<div class="frontpage-app-icon-wrap">
|
||||
<img src="${icon}" alt="${shortName}" onerror="this.src='/icons/apps/default.svg'">
|
||||
<div class="frontpage-app-overlay" id="frontpage-overlay-${appName}" onclick="event.stopPropagation()"></div>
|
||||
@ -103,12 +103,12 @@ function setupEventListeners() {
|
||||
function navigateToApp(appName) {
|
||||
// Use proper SPA navigation to the app page
|
||||
if (window.librePortalSPA && typeof window.librePortalSPA.navigate === 'function') {
|
||||
window.librePortalSPA.navigate(`/app?=${appName}`);
|
||||
window.librePortalSPA.navigate(`/app/${appName}`);
|
||||
} else if (window.navigateToRoute && typeof window.navigateToRoute === 'function') {
|
||||
window.navigateToRoute(`app?=${appName}`);
|
||||
window.navigateToRoute(`app/${appName}`);
|
||||
} else {
|
||||
// Fallback to direct navigation
|
||||
window.location.href = `/app?=${appName}`;
|
||||
window.location.href = `/app/${appName}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -346,7 +346,7 @@ window.handleNotificationNavigation = (url) => {
|
||||
// We're on an app page - navigate to the specified app and tab
|
||||
if (window.appTabbedManager) {
|
||||
// Update the URL to the target app/tab/task
|
||||
const newUrl = `/app?=${appName}&tab=${tab}&task=${taskId}`;
|
||||
const newUrl = `/app/${appName}?tab=${tab}&task=${taskId}`;
|
||||
console.log('🔗 Pushing state to URL:', newUrl);
|
||||
window.history.pushState({}, '', newUrl);
|
||||
|
||||
@ -402,7 +402,7 @@ window.handleNotificationNavigation = (url) => {
|
||||
// We're on the tasks page, navigate to the specified task
|
||||
if (taskId) {
|
||||
console.log('🔗 On tasks page, opening task:', taskId);
|
||||
window.history.pushState({}, '', `/tasks?=all&task=${taskId}`);
|
||||
window.history.pushState({}, '', `/tasks/all?task=${taskId}`);
|
||||
setTimeout(() => {
|
||||
if (typeof window.toggleTaskDetails === 'function') {
|
||||
console.log('🔗 Opening task details for:', taskId);
|
||||
@ -414,7 +414,7 @@ window.handleNotificationNavigation = (url) => {
|
||||
} else {
|
||||
// Not on app or tasks page - navigate to the app's tasks tab
|
||||
if (appName && tab) {
|
||||
window.history.pushState({}, '', `/app?=${appName}&tab=${tab}&task=${taskId}`);
|
||||
window.history.pushState({}, '', `/app/${appName}?tab=${tab}&task=${taskId}`);
|
||||
// Let the SPA handle the navigation
|
||||
if (window.appTabbedManager) {
|
||||
window.appTabbedManager.showAppDetail(appName);
|
||||
|
||||
@ -295,10 +295,10 @@ async configUpdate(changes) {
|
||||
let taskUrl;
|
||||
const currentUrl = window.location.href;
|
||||
|
||||
if (currentUrl.includes('/app?=') && appName) {
|
||||
taskUrl = `/app?=${appName}&tab=tasks&task=${task.id}`;
|
||||
if (currentUrl.includes('/app/') && appName) {
|
||||
taskUrl = `/app/${appName}?tab=tasks&task=${task.id}`;
|
||||
} else {
|
||||
taskUrl = `/tasks?=all&task=${task.id}`;
|
||||
taskUrl = `/tasks/all?task=${task.id}`;
|
||||
}
|
||||
|
||||
if (window.notificationSystem) {
|
||||
@ -364,12 +364,12 @@ async configUpdate(changes) {
|
||||
// console.log('🔍 TaskActions: Current URL:', currentUrl);
|
||||
|
||||
// Always generate URL with app name for proper navigation
|
||||
if (currentUrl.includes('/app?=') && appName) {
|
||||
if (currentUrl.includes('/app/') && appName) {
|
||||
// We're on an app page, maintain app context
|
||||
taskUrl = `/app?=${appName}&tab=tasks&task=${task.id}`;
|
||||
taskUrl = `/app/${appName}?tab=tasks&task=${task.id}`;
|
||||
} else {
|
||||
// We're on main tasks page, use normal URL
|
||||
taskUrl = `/tasks?=all&task=${task.id}`;
|
||||
taskUrl = `/tasks/all?task=${task.id}`;
|
||||
}
|
||||
|
||||
// Show success notification with app icon and direct link
|
||||
|
||||
@ -122,11 +122,12 @@ class TasksManager {
|
||||
const searchParams = currentUrl.searchParams;
|
||||
|
||||
// Check if we're on the main tasks page (not app page)
|
||||
const isMainTasksPage = currentUrl.pathname === '/tasks' || currentUrl.pathname === '/tasks.html';
|
||||
const isMainTasksPage = currentUrl.pathname === '/tasks' || currentUrl.pathname.startsWith('/tasks/') || currentUrl.pathname === '/tasks.html';
|
||||
|
||||
if (isMainTasksPage) {
|
||||
// On main tasks page, get category from URL
|
||||
this.currentCategory = searchParams.get('') || 'all';
|
||||
// Category from the path (/tasks/<category>), else legacy ?=<category>.
|
||||
const seg = currentUrl.pathname.replace(/^\/tasks\/?/, '').split('/')[0];
|
||||
this.currentCategory = seg || searchParams.get('') || 'all';
|
||||
|
||||
// Only check for specific task parameter if we're not coming from an app page
|
||||
const taskParam = searchParams.get('task');
|
||||
@ -149,9 +150,9 @@ class TasksManager {
|
||||
|
||||
updateURL(category, taskId = null) {
|
||||
// Update URL without page reload and without hash
|
||||
let newURL = `/tasks?=${category}`;
|
||||
let newURL = `/tasks/${category || 'all'}`;
|
||||
if (taskId) {
|
||||
newURL += `&task=${taskId}`;
|
||||
newURL += `?task=${taskId}`;
|
||||
}
|
||||
|
||||
// Prevent the SPA from interfering
|
||||
@ -619,13 +620,13 @@ class TasksManager {
|
||||
<!-- Task metadata -->
|
||||
<div class="task-meta">
|
||||
<div class="meta-item">
|
||||
<strong>Task ID:</strong> <a href="/tasks?=all&task=${task.id}" class="task-id-link" data-task-id="${task.id}">${task.id}</a>
|
||||
<strong>Task ID:</strong> <a href="/tasks/all?task=${task.id}" class="task-id-link" data-task-id="${task.id}">${task.id}</a>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<strong>Type:</strong> ${task.type || 'unknown'}
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<strong>App:</strong> ${task.app ? `<a href="/app?=${task.app}" class="task-app-link" data-app-name="${task.app}">${task.app}</a>` : 'system'}
|
||||
<strong>App:</strong> ${task.app ? `<a href="/app/${task.app}" class="task-app-link" data-app-name="${task.app}">${task.app}</a>` : 'system'}
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<strong>Created:</strong> ${new Date(task.createdAt).toLocaleString()}
|
||||
@ -1334,7 +1335,7 @@ class TasksManager {
|
||||
|
||||
// Show success notification with app icon and direct link
|
||||
if (window.notificationSystem) {
|
||||
const taskUrl = `/tasks?=all&task=${task.id}`;
|
||||
const taskUrl = `/tasks/all?task=${task.id}`;
|
||||
const typeIcon = this.getTaskTypeIcon ? this.getTaskTypeIcon({ type: action })?.icon : '';
|
||||
const customIcon = typeIcon ? `<span style="font-size:18px;line-height:1;">${typeIcon}</span>` : null;
|
||||
window.notificationSystem.show(
|
||||
@ -1455,8 +1456,8 @@ class TasksManager {
|
||||
const subjectLabel = isSystemTask ? 'System' : 'App';
|
||||
const onAppPage = window.location.pathname.startsWith('/app') && !window.location.pathname.startsWith('/apps');
|
||||
const url = (onAppPage && appName)
|
||||
? `/app?=${appName}&tab=tasks&task=${taskId}`
|
||||
: `/tasks?=all&task=${taskId}`;
|
||||
? `/app/${appName}?tab=tasks&task=${taskId}`
|
||||
: `/tasks/all?task=${taskId}`;
|
||||
const icon = appName ? `icons/apps/${appName}.svg` : null;
|
||||
|
||||
// Match the per-action emoji used in the task list rows (see
|
||||
|
||||
@ -145,7 +145,7 @@ class TopbarComponent {
|
||||
window.tasksManager.tasks = []; // Clear the task list
|
||||
|
||||
// Clear URL parameters
|
||||
window.history.pushState({ category: 'all', taskId: null }, '', '/tasks?=all');
|
||||
window.history.pushState({ category: 'all', taskId: null }, '', '/tasks/all');
|
||||
|
||||
// Clear any localStorage filters
|
||||
localStorage.removeItem('tasksDefaultFilter');
|
||||
|
||||
@ -66,8 +66,9 @@ class LibrePortalSPAClean {
|
||||
this.routes.set('/', () => this.handleDashboard());
|
||||
this.routes.set('/dashboard', () => this.handleDashboard());
|
||||
this.routes.set('/apps', () => this.handleApps());
|
||||
this.routes.set('/app', () => this.handleAppDetail()); // Handle /app without query
|
||||
this.routes.set('/app*', () => this.handleAppDetail()); // Handle /app with query
|
||||
this.routes.set('/apps*', () => this.handleApps()); // /apps/<category> — MUST precede /app* (/apps startsWith /app)
|
||||
this.routes.set('/app', () => this.handleAppDetail()); // /app/<name>
|
||||
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
|
||||
@ -279,17 +280,17 @@ class LibrePortalSPAClean {
|
||||
async handleApps() {
|
||||
//console.log('📱 Loading apps...');
|
||||
|
||||
// Handle query parameters for apps
|
||||
const path = window.location.pathname + window.location.search;
|
||||
if (path.includes('?=')) {
|
||||
const [basePath, query] = path.split('?=');
|
||||
window.appsCategory = query || 'all';
|
||||
} else if (path.includes('?')) {
|
||||
const url = new URL(path, window.location.origin);
|
||||
const searchParams = url.searchParams;
|
||||
window.appsCategory = searchParams.get('apps') || 'all';
|
||||
// Category from the path (/apps/<category>), else legacy ?=<cat> / ?apps=.
|
||||
const seg = window.location.pathname.replace(/^\/apps\/?/, '').split('/')[0];
|
||||
if (seg) {
|
||||
window.appsCategory = decodeURIComponent(seg);
|
||||
} else {
|
||||
window.appsCategory = 'all';
|
||||
const search = window.location.search || '';
|
||||
if (search.includes('?=')) {
|
||||
window.appsCategory = (window.location.pathname + search).split('?=')[1] || 'all';
|
||||
} else {
|
||||
window.appsCategory = new URLSearchParams(search).get('apps') || 'all';
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@ -321,9 +322,12 @@ class LibrePortalSPAClean {
|
||||
async handleAppDetail() {
|
||||
//console.log('🔍 Loading app detail...');
|
||||
|
||||
// Extract app name from URL
|
||||
// Extract app name. Path-based /app/<name> first, then legacy ?app= / ?=name.
|
||||
const url = new URL(window.location);
|
||||
let appName = url.searchParams.get('app');
|
||||
let appName = url.pathname.replace(/^\/app\/?/, '').split('/')[0];
|
||||
appName = appName ? decodeURIComponent(appName) : '';
|
||||
|
||||
if (!appName) appName = url.searchParams.get('app');
|
||||
|
||||
// Handle old format ?=appname&tab=tabname
|
||||
if (!appName && url.search.includes('?=')) {
|
||||
|
||||
@ -142,13 +142,13 @@
|
||||
}
|
||||
|
||||
function navigateToRecommendedApps() {
|
||||
const route = '/apps?=recommended';
|
||||
const route = '/apps/recommended';
|
||||
if (window.spaClean && typeof window.spaClean.navigate === 'function') {
|
||||
window.spaClean.navigate(route);
|
||||
} else if (typeof window.navigateToRoute === 'function') {
|
||||
window.navigateToRoute(route);
|
||||
} else {
|
||||
window.location.href = 'apps.html?=recommended';
|
||||
window.location.href = '/apps/recommended';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -147,7 +147,7 @@ async function initializeData() {
|
||||
if (currentPath === '/dashboard' || currentPath === '/') {
|
||||
// Dashboard: Only installed apps + system info (no categories needed)
|
||||
await loadDashboardData();
|
||||
} else if (currentPath === '/apps' || currentPath === '/app' || searchParams.has('apps') || searchParams.has('app')) {
|
||||
} else if (currentPath.startsWith('/apps') || currentPath.startsWith('/app') || searchParams.has('apps') || searchParams.has('app')) {
|
||||
// Apps page: All apps + categories (no system configs needed)
|
||||
await loadAppsPageData();
|
||||
} else if (currentPath.startsWith('/admin') || currentPath.startsWith('/config') || currentPath.startsWith('/ssh') || searchParams.has('config')) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user