Merge claude/2
This commit is contained in:
commit
338cd801fd
@ -78,6 +78,38 @@ class TasksManager {
|
|||||||
return action.split(/[_-]/).map(w => w ? w.charAt(0).toUpperCase() + w.slice(1) : '').join(' ');
|
return action.split(/[_-]/).map(w => w ? w.charAt(0).toUpperCase() + w.slice(1) : '').join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shared "task → notification payload" resolver. Every task surface
|
||||||
|
// (started/completed toast, delete modal, delete confirmation) builds
|
||||||
|
// the same identity (display name, app icon, friendly action title,
|
||||||
|
// emoji type-icon) — keep it in one place so they read consistently.
|
||||||
|
_taskNotificationDescriptor(task) {
|
||||||
|
const appName = (task && task.app) || null;
|
||||||
|
const action = (task && task.type) || '';
|
||||||
|
const isSystemTask = action.startsWith('setup-') || appName === 'system';
|
||||||
|
let actionTitle = this.formatActionTitle(action);
|
||||||
|
// Tool tasks: prefer the catalog-defined label.
|
||||||
|
const toolCmdMatch = ((task && task.command) || '').match(/libreportal app tool (\S+) (\S+)/);
|
||||||
|
if (toolCmdMatch) {
|
||||||
|
const toolId = toolCmdMatch[2];
|
||||||
|
let toolLabel = null;
|
||||||
|
const cat = window.toolsCatalog;
|
||||||
|
if (cat && cat.apps && cat.apps[toolCmdMatch[1]] && Array.isArray(cat.apps[toolCmdMatch[1]].tools)) {
|
||||||
|
const t = cat.apps[toolCmdMatch[1]].tools.find(x => x.id === toolId);
|
||||||
|
if (t && t.label) toolLabel = t.label;
|
||||||
|
}
|
||||||
|
if (!toolLabel) toolLabel = toolId.split(/[_-]/).map(w => w ? w.charAt(0).toUpperCase() + w.slice(1) : '').join(' ');
|
||||||
|
actionTitle = toolLabel;
|
||||||
|
}
|
||||||
|
const displayName = isSystemTask
|
||||||
|
? 'LibrePortal'
|
||||||
|
: ((appName && window.getAppDisplayName) ? window.getAppDisplayName(appName) : (appName || ''));
|
||||||
|
const icon = isSystemTask
|
||||||
|
? '/icons/libreportal.svg'
|
||||||
|
: (appName ? `/icons/apps/${encodeURIComponent(appName)}.svg` : null);
|
||||||
|
const typeIcon = (this.getTaskTypeIcon ? this.getTaskTypeIcon(task)?.icon : '') || '';
|
||||||
|
return { appName, isSystemTask, actionTitle, displayName, icon, typeIcon };
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize task system after scripts are loaded
|
// Initialize task system after scripts are loaded
|
||||||
initializeTaskSystem() {
|
initializeTaskSystem() {
|
||||||
try {
|
try {
|
||||||
@ -1402,49 +1434,13 @@ class TasksManager {
|
|||||||
// Layout matches the "<App> task started!" format used by task-actions
|
// Layout matches the "<App> task started!" format used by task-actions
|
||||||
// and backup-manager so started/completed look like a matched pair.
|
// and backup-manager so started/completed look like a matched pair.
|
||||||
if (window.notificationSystem && task) {
|
if (window.notificationSystem && task) {
|
||||||
const appName = task.app || null;
|
const { appName, actionTitle, displayName, icon, typeIcon } = this._taskNotificationDescriptor(task);
|
||||||
const action = task.type || 'task';
|
|
||||||
let actionTitle = this.formatActionTitle(action);
|
|
||||||
// Tool tasks: override the generic "Tool" label with the tool's
|
|
||||||
// friendly name (e.g. "Manage Shortcuts") so completion toasts
|
|
||||||
// match what the user clicked.
|
|
||||||
const toolCmdMatch = (task.command || '').match(/libreportal app tool (\S+) (\S+)/);
|
|
||||||
if (toolCmdMatch) {
|
|
||||||
const toolApp = toolCmdMatch[1];
|
|
||||||
const toolId = toolCmdMatch[2];
|
|
||||||
let toolLabel = null;
|
|
||||||
const cat = window.toolsCatalog;
|
|
||||||
if (cat && cat.apps && cat.apps[toolApp] && Array.isArray(cat.apps[toolApp].tools)) {
|
|
||||||
const t = cat.apps[toolApp].tools.find(x => x.id === toolId);
|
|
||||||
if (t && t.label) toolLabel = t.label;
|
|
||||||
}
|
|
||||||
if (!toolLabel) {
|
|
||||||
toolLabel = toolId.split('_').map(w => w ? w.charAt(0).toUpperCase() + w.slice(1) : '').join(' ');
|
|
||||||
}
|
|
||||||
actionTitle = toolLabel;
|
|
||||||
}
|
|
||||||
// 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 onAppPage = window.location.pathname.startsWith('/app') && !window.location.pathname.startsWith('/apps');
|
const onAppPage = window.location.pathname.startsWith('/app') && !window.location.pathname.startsWith('/apps');
|
||||||
const url = (onAppPage && appName)
|
const url = (onAppPage && appName)
|
||||||
? window.appPath(appName, 'tasks', null, taskId)
|
? window.appPath(appName, 'tasks', null, taskId)
|
||||||
: `/tasks/all?task=${taskId}`;
|
: `/tasks/all?task=${taskId}`;
|
||||||
const icon = isSystemTask
|
// Per-action emoji (install ✅, backup 💾, restore 📦, …) in the
|
||||||
? '/icons/libreportal.svg'
|
// notification's leftmost icon slot, mirroring task-list rows.
|
||||||
: (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
|
|
||||||
// notification's leftmost icon slot shows the task *type* (install
|
|
||||||
// ✅, backup 💾, restore 📦, …) instead of the generic level tick.
|
|
||||||
const typeIcon = (this.getTaskTypeIcon ? this.getTaskTypeIcon(task) : null)?.icon || '';
|
|
||||||
const customIcon = typeIcon ? `<span style="font-size:18px;line-height:1;">${typeIcon}</span>` : null;
|
const customIcon = typeIcon ? `<span style="font-size:18px;line-height:1;">${typeIcon}</span>` : null;
|
||||||
|
|
||||||
let body;
|
let body;
|
||||||
@ -2196,11 +2192,16 @@ class TasksManager {
|
|||||||
this.generateAppCategories();
|
this.generateAppCategories();
|
||||||
|
|
||||||
if (window.notificationSystem) {
|
if (window.notificationSystem) {
|
||||||
// Type icon from whatever the task was, with a trash fallback
|
// Match the "<App> task <verb>" two-line shape used by started/
|
||||||
// because deletion is conceptually a 🗑️ action.
|
// completed/failed/cancelled so deletion reads as part of the same
|
||||||
const typeIcon = (task && this.getTaskTypeIcon ? this.getTaskTypeIcon(task)?.icon : '') || '🗑️';
|
// family. Type emoji falls back to 🗑️ since deletion is a 🗑️ action.
|
||||||
const customIcon = `<span style="font-size:18px;line-height:1;">${typeIcon}</span>`;
|
const { appName, actionTitle, displayName, icon, typeIcon } = this._taskNotificationDescriptor(task);
|
||||||
window.notificationSystem.show('Task deleted successfully', 'info', null, null, null, customIcon);
|
const emoji = typeIcon || '🗑️';
|
||||||
|
const customIcon = `<span style="font-size:18px;line-height:1;">${emoji}</span>`;
|
||||||
|
const body = displayName
|
||||||
|
? `<strong>${displayName}</strong><br>${actionTitle} task deleted.`
|
||||||
|
: `${actionTitle || 'Task'} deleted.`;
|
||||||
|
window.notificationSystem.show(body, 'info', appName, null, icon, customIcon);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deleting task:', error);
|
console.error('Error deleting task:', error);
|
||||||
@ -2219,36 +2220,15 @@ class TasksManager {
|
|||||||
const escHtml = (s) => String(s == null ? '' : s)
|
const escHtml = (s) => String(s == null ? '' : s)
|
||||||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
|
||||||
// Build a friendly title + app icon so the modal reads "Install Ipinfo"
|
// Friendly title + app icon — mirrors the completion-toast format so
|
||||||
// with the app's logo, not the raw "libreportal app install ipinfo"
|
// the modal's identity matches every other surface.
|
||||||
// command. Mirrors the completion-notification flow above so the
|
const { isSystemTask, actionTitle, displayName, icon: taskIcon } = this._taskNotificationDescriptor(task);
|
||||||
// visual identity of a task is consistent across surfaces.
|
// For the modal we omit the "LibrePortal" subject (the eyebrow already
|
||||||
const appName = (task && task.app) || null;
|
// says "Delete Task") and just lead with the action: "Update Config".
|
||||||
const action = (task && task.type) || '';
|
const modalSubject = isSystemTask ? '' : displayName;
|
||||||
const isSystemTask = action.startsWith('setup-') || appName === 'system';
|
const taskLabel = modalSubject
|
||||||
let actionTitle = this.formatActionTitle(action);
|
? `${actionTitle} ${modalSubject}`
|
||||||
// Tool tasks: prefer the tool's curated label.
|
|
||||||
const toolCmdMatch = (task && task.command || '').match(/libreportal app tool (\S+) (\S+)/);
|
|
||||||
if (toolCmdMatch) {
|
|
||||||
const toolId = toolCmdMatch[2];
|
|
||||||
let toolLabel = null;
|
|
||||||
const cat = window.toolsCatalog;
|
|
||||||
if (cat && cat.apps && cat.apps[toolCmdMatch[1]] && Array.isArray(cat.apps[toolCmdMatch[1]].tools)) {
|
|
||||||
const t = cat.apps[toolCmdMatch[1]].tools.find(x => x.id === toolId);
|
|
||||||
if (t && t.label) toolLabel = t.label;
|
|
||||||
}
|
|
||||||
if (!toolLabel) toolLabel = toolId.split(/[_-]/).map(w => w ? w.charAt(0).toUpperCase() + w.slice(1) : '').join(' ');
|
|
||||||
actionTitle = toolLabel;
|
|
||||||
}
|
|
||||||
const displayName = isSystemTask
|
|
||||||
? ''
|
|
||||||
: ((appName && window.getAppDisplayName) ? window.getAppDisplayName(appName) : (appName || ''));
|
|
||||||
const taskLabel = displayName
|
|
||||||
? `${actionTitle} ${displayName}`
|
|
||||||
: (actionTitle || (task && task.id) || 'Unknown task');
|
: (actionTitle || (task && task.id) || 'Unknown task');
|
||||||
const taskIcon = isSystemTask
|
|
||||||
? '/icons/libreportal.svg'
|
|
||||||
: (appName ? `/icons/apps/${encodeURIComponent(appName)}.svg` : null);
|
|
||||||
const taskStatus = (task && task.status) || 'unknown';
|
const taskStatus = (task && task.status) || 'unknown';
|
||||||
|
|
||||||
const warningTitle = isActive ? 'Active task' : 'This cannot be undone';
|
const warningTitle = isActive ? 'Active task' : 'This cannot be undone';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user