Merge claude/1

This commit is contained in:
librelad 2026-05-27 01:16:43 +01:00
commit cd30d90a81
3 changed files with 23 additions and 110 deletions

View File

@ -774,7 +774,7 @@ class AppTabbedManager {
if (this.runningTasks.has(key)) {
const existing = this.runningTasks.get(key);
// Same task firing twice — `createAndExecuteTask` dispatches taskCreated
// Same task firing twice — executeTask dispatches taskCreated
// synchronously, and the SSE bus also dispatches it when the new task
// file shows up. Both events carry the same taskId; treat as a no-op.
if (existing && existing.taskId === taskId) return;

View File

@ -302,7 +302,15 @@ async configUpdate(changes) {
}
if (window.notificationSystem) {
const displayName = window.getAppDisplayName ? window.getAppDisplayName(appName) : appName;
// `appName === 'system'` is a category sentinel (config_update,
// system_update — no real app). Resolve it to the LibrePortal
// logo + name so the toast doesn't read "App: System" with a
// broken /icons/apps/system.svg.
const isSystem = appName === 'system';
const displayName = isSystem
? 'LibrePortal'
: (window.getAppDisplayName ? window.getAppDisplayName(appName) : appName);
const notifIcon = isSystem ? '/icons/libreportal.svg' : appIcon;
const typeIcon = (window.tasksManager && window.tasksManager.getTaskTypeIcon
? window.tasksManager.getTaskTypeIcon({ type: action })
: null)?.icon || '';
@ -311,11 +319,11 @@ async configUpdate(changes) {
? `${displayLabel} task started!`
: `${action.charAt(0).toUpperCase() + action.slice(1)} task started!`;
window.notificationSystem.show(
`<strong>App: ${displayName}</strong><br>${headline}`,
`<strong>${displayName}</strong><br>${headline}`,
'success',
appName,
taskUrl,
appIcon,
notifIcon,
customIcon
);
}
@ -330,64 +338,7 @@ async configUpdate(changes) {
}
}
/**
* Execute task monitoring (separated to avoid duplicate task creation)
*/
async executeTaskMonitoring(task, appName, action) {
// Emit task creation event for AppTabbedManager
window.dispatchEvent(new CustomEvent('taskCreated', {
detail: {
taskId: task.id,
appName: appName,
action: action,
timestamp: Date.now()
}
}));
// console.log(`✅ Task created: ${task.id} for ${action} on ${appName}`);
// Set up monitoring for this specific task
this.tasksManager.monitorTask(task.id, appName, action);
// Try to get app data for better notifications
let appData = null;
try {
appData = this.commands.getAppData ? this.commands.getAppData(appName) : null;
} catch (error) {
console.warn('Could not get app data:', error);
}
const appIcon = appData?.icon || `/icons/apps/${task.app}.svg`;
// Smart URL generation - always include app name
let taskUrl;
const currentUrl = window.location.href;
// console.log('🔍 TaskActions: Current URL:', currentUrl);
// Always generate URL with app name for proper navigation
if (currentUrl.includes('/app/') && appName) {
// We're on an app page, maintain app context
taskUrl = `/app/${appName}?tab=tasks&task=${task.id}`;
} else {
// We're on main tasks page, use normal URL
taskUrl = `/tasks/all?task=${task.id}`;
}
// Show success notification with app icon and direct link
if (window.notificationSystem) {
const displayName = window.getAppDisplayName ? window.getAppDisplayName(appName) : appName;
window.notificationSystem.show(
`<strong>App: ${displayName}</strong><br>
${action.charAt(0).toUpperCase() + action.slice(1)} task started!`,
'success',
appName,
taskUrl,
appIcon
);
}
return task;
}
/**
* Update task in the manager
*/

View File

@ -1320,48 +1320,6 @@ class TasksManager {
}
};
window.createAndExecuteTask = async (action, appName, config = '') => {
try {
// Create task using NEW signature
const task = await this.taskManager.createTask(`libreportal app ${action} ${appName}`, action, appName, config);
// Emit task creation event for AppTabbedManager
window.dispatchEvent(new CustomEvent('taskCreated', {
detail: {
taskId: task.id,
appName: appName,
action: action,
timestamp: Date.now()
}
}));
// Set up monitoring for this specific task
this.monitorTask(task.id, appName, action);
// Show success notification with app icon and direct link
if (window.notificationSystem) {
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(
`Task created: ${action} ${appName}`,
'info',
appName,
taskUrl,
`/icons/apps/${appName}.svg`,
customIcon
);
}
return task;
} catch (error) {
console.error(`❌ Failed to create ${action} task for ${appName}:`, error);
if (window.notificationSystem) {
window.notificationSystem.error(`Failed to start ${action} task for ${appName}: ${error.message}`);
}
throw error;
}
};
}
// Single page-wide subscription to the TaskEventBus. This complements
@ -1452,18 +1410,22 @@ class TasksManager {
}
actionTitle = toolLabel;
}
const isSystemTask = action.startsWith('setup-');
// System-level tasks resolve to LibrePortal as the subject + use the
// LibrePortal logo as the app-icon. Covers `app: 'system'` (config
// update, system update) and `setup-*` types (setup wizard phases).
const isSystemTask = action.startsWith('setup-') || appName === 'system';
const displayName = isSystemTask
? 'LibrePortal'
: ((appName && window.getAppDisplayName)
? window.getAppDisplayName(appName)
: (appName || (task.command || `Task ${taskId}`)));
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}`;
const icon = appName ? `/icons/apps/${appName}.svg` : null;
const icon = isSystemTask
? '/icons/libreportal.svg'
: (appName ? `/icons/apps/${appName}.svg` : null);
// Match the per-action emoji used in the task list rows (see
// `getTaskTypeIcon`). Passed as the 6th `customIcon` arg so the
@ -1475,13 +1437,13 @@ class TasksManager {
let body;
let level;
if (task.status === 'completed') {
body = `<strong>${subjectLabel}: ${displayName}</strong><br>${actionTitle} task completed!`;
body = `<strong>${displayName}</strong><br>${actionTitle} task completed!`;
level = 'success';
} else if (task.status === 'failed') {
body = `<strong>${subjectLabel}: ${displayName}</strong><br>${actionTitle} task failed.`;
body = `<strong>${displayName}</strong><br>${actionTitle} task failed.`;
level = 'error';
} else if (task.status === 'cancelled') {
body = `<strong>${subjectLabel}: ${displayName}</strong><br>${actionTitle} task cancelled.`;
body = `<strong>${displayName}</strong><br>${actionTitle} task cancelled.`;
level = 'warning';
}
if (body) window.notificationSystem.show(body, level, appName, url, icon, customIcon);