Compare commits
2 Commits
12a37cc734
...
86abfadb52
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86abfadb52 | ||
|
|
9582671072 |
@ -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(window.taskPath('all', task.id)), 400);
|
||||
} else if (task && window.navigateToRoute) {
|
||||
setTimeout(() => window.navigateToRoute(`tasks/all?task=${task.id}`), 400);
|
||||
setTimeout(() => window.navigateToRoute(window.taskPath('all', task.id)), 400);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('ConfigForm: Error saving configuration:', error);
|
||||
|
||||
@ -213,7 +213,7 @@ Object.assign(TasksManager.prototype, {
|
||||
<!-- 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="${window.taskPath ? window.taskPath('all', task.id) : '/tasks/all'}" class="task-id-link" data-task-id="${task.id}">${task.id}</a>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<strong>Type:</strong> ${task.type || 'unknown'}
|
||||
|
||||
@ -142,18 +142,13 @@ class TasksManager {
|
||||
const isMainTasksPage = currentUrl.pathname === '/tasks' || currentUrl.pathname.startsWith('/tasks/') || currentUrl.pathname === '/tasks.html';
|
||||
|
||||
if (isMainTasksPage) {
|
||||
// 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');
|
||||
if (taskParam) {
|
||||
this.highlightedTaskId = taskParam;
|
||||
} else {
|
||||
// Clear any existing highlighted task when on main tasks page without task param
|
||||
this.highlightedTaskId = null;
|
||||
}
|
||||
// Category + single-task deep link from the path (/tasks/<category>/<id>),
|
||||
// with legacy ?=<category> and ?task=<id> queries still honoured.
|
||||
const parts = (typeof window.taskPartsFromPath === 'function')
|
||||
? window.taskPartsFromPath(currentUrl.pathname, currentUrl.search)
|
||||
: { category: '', taskId: searchParams.get('task') || '' };
|
||||
this.currentCategory = parts.category || searchParams.get('') || 'all';
|
||||
this.highlightedTaskId = parts.taskId || null;
|
||||
} else {
|
||||
// Not on main tasks page, get default filter from localStorage
|
||||
this.currentCategory = localStorage.getItem('tasksDefaultFilter') || 'all';
|
||||
@ -163,11 +158,11 @@ class TasksManager {
|
||||
}
|
||||
|
||||
updateURL(category, taskId = null) {
|
||||
// Update URL without page reload and without hash
|
||||
let newURL = `/tasks/${category || 'all'}`;
|
||||
if (taskId) {
|
||||
newURL += `?task=${taskId}`;
|
||||
}
|
||||
// Update URL without page reload and without hash. The task deep link is a
|
||||
// path segment (/tasks/<category>/<id>) — see window.taskPath.
|
||||
const newURL = (typeof window.taskPath === 'function')
|
||||
? window.taskPath(category, taskId)
|
||||
: `/tasks/${category || 'all'}${taskId ? '/' + String(taskId).replace(/^task_/, '') : ''}`;
|
||||
|
||||
// Prevent the SPA from interfering
|
||||
if (window.librePortalSPA) {
|
||||
@ -184,7 +179,7 @@ class TasksManager {
|
||||
//// // console.log('🔧 Initializing TasksManager...');
|
||||
|
||||
// Re-read the URL on every (re)mount. The SPA reuses this singleton, so a
|
||||
// navigation to /tasks/<cat>?task=X must refresh the category + deep-link
|
||||
// navigation to /tasks/<cat>/<id> must refresh the category + deep-link
|
||||
// state — a constructor-only read goes stale after the first visit.
|
||||
this.initializeFromURL();
|
||||
|
||||
@ -415,7 +410,7 @@ class TasksManager {
|
||||
const onAppPage = window.location.pathname.startsWith('/app') && !window.location.pathname.startsWith('/apps');
|
||||
const url = (onAppPage && appName)
|
||||
? window.appPath(appName, 'tasks', null, taskId)
|
||||
: `/tasks/all?task=${taskId}`;
|
||||
: window.taskPath('all', taskId);
|
||||
// Per-action emoji (install ✅, backup 💾, restore 📦, …) in the
|
||||
// notification's leftmost icon slot, mirroring task-list rows.
|
||||
const customIcon = typeIcon ? `<span style="font-size:18px;line-height:1;">${typeIcon}</span>` : null;
|
||||
|
||||
@ -657,6 +657,27 @@ window.appPartsFromPath = function (pathname) {
|
||||
return { app, tab, sub };
|
||||
};
|
||||
|
||||
// Global tasks page path helpers — bring the single-task deep link in line with
|
||||
// /app/<name> and /admin/<…>: it's a path segment (/tasks/<category>/<id>), not
|
||||
// a ?task= query. Task ids are guaranteed `task_<digits>_<base36>`, so the
|
||||
// `task_` prefix is dropped in the URL for brevity and restored on read. A
|
||||
// legacy ?task=<id> query is still parsed so older links and bookmarks resolve.
|
||||
window.taskPath = function (category, taskId) {
|
||||
let p = '/tasks/' + encodeURIComponent(category || 'all');
|
||||
if (taskId) p += '/' + encodeURIComponent(String(taskId).replace(/^task_/, ''));
|
||||
return p;
|
||||
};
|
||||
window.taskPartsFromPath = function (pathname, search) {
|
||||
const segs = String(pathname || '').replace(/^\/tasks\/?/, '').split('/').filter(Boolean);
|
||||
const category = segs[0] || '';
|
||||
let taskId = segs[1] ? decodeURIComponent(segs[1]) : '';
|
||||
if (!taskId && search) {
|
||||
try { taskId = new URLSearchParams(search).get('task') || ''; } catch (_) {}
|
||||
}
|
||||
if (taskId && !/^task_/.test(taskId)) taskId = 'task_' + taskId;
|
||||
return { category, taskId };
|
||||
};
|
||||
|
||||
// Global navigation function for click handlers
|
||||
window.navigateToRoute = function(href) {
|
||||
if (window.spaClean) {
|
||||
|
||||
@ -114,7 +114,7 @@ class NotificationSystem {
|
||||
// Action button (context-aware)
|
||||
if (appName && appUrl) {
|
||||
let buttonText = 'Manage';
|
||||
if (appUrl.includes('task=')) {
|
||||
if (appUrl.includes('task=') || /\/tasks\/[^/]+\/[^/?]+/.test(appUrl)) {
|
||||
buttonText = 'View Task';
|
||||
} else if (type === 'success' && message.includes('install')) {
|
||||
buttonText = 'Configure';
|
||||
@ -399,14 +399,17 @@ window.handleNotificationNavigation = (url) => {
|
||||
console.warn('⚠️ appTabbedManager not available');
|
||||
}
|
||||
} else if (currentPath.includes('/tasks')) {
|
||||
// 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}`);
|
||||
// We're on the tasks page, navigate to the specified task. The target may
|
||||
// carry the id as a /tasks/<cat>/<id> path segment or a legacy ?task=.
|
||||
const tasksTaskId = taskId
|
||||
|| (window.taskPartsFromPath ? window.taskPartsFromPath(urlObj.pathname, urlObj.search).taskId : '');
|
||||
if (tasksTaskId) {
|
||||
console.log('🔗 On tasks page, opening task:', tasksTaskId);
|
||||
window.history.pushState({}, '', window.taskPath ? window.taskPath('all', tasksTaskId) : url);
|
||||
setTimeout(() => {
|
||||
if (typeof window.toggleTaskDetails === 'function') {
|
||||
console.log('🔗 Opening task details for:', taskId);
|
||||
window.toggleTaskDetails(taskId);
|
||||
console.log('🔗 Opening task details for:', tasksTaskId);
|
||||
window.toggleTaskDetails(tasksTaskId);
|
||||
}
|
||||
}, 300);
|
||||
return true;
|
||||
|
||||
@ -784,10 +784,11 @@ class SetupWizard {
|
||||
|
||||
this.container.classList.add('setup-launched');
|
||||
setTimeout(() => {
|
||||
// Path-based route (the app uses /… URLs); the specific task is still
|
||||
// selected via ?task=. Navigate via the SPA helper, with an absolute-path
|
||||
// full-load fallback.
|
||||
const target = `/tasks/all?task=${encodeURIComponent(firstTaskId)}&from=setup`;
|
||||
// Path-based route (the app uses /… URLs); the specific task is a path
|
||||
// segment (/tasks/all/<id>) and ?from=setup flags the install handoff so
|
||||
// the page follows the running queue. Navigate via the SPA helper, with
|
||||
// an absolute-path full-load fallback.
|
||||
const target = `${window.taskPath('all', firstTaskId)}?from=setup`;
|
||||
if (typeof window.navigateToRoute === 'function' && window.spaClean) {
|
||||
window.navigateToRoute(target);
|
||||
this.hide();
|
||||
|
||||
@ -406,7 +406,7 @@ async configUpdate(changes) {
|
||||
if (currentUrl.includes('/app/') && appName) {
|
||||
taskUrl = window.appPath(appName, 'tasks', null, task.id);
|
||||
} else {
|
||||
taskUrl = `/tasks/all?task=${task.id}`;
|
||||
taskUrl = window.taskPath('all', task.id);
|
||||
}
|
||||
|
||||
if (window.notificationSystem) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user