diff --git a/containers/libreportal/frontend/css/topbar.css b/containers/libreportal/frontend/css/topbar.css
index 0b510b9..71f07f7 100644
--- a/containers/libreportal/frontend/css/topbar.css
+++ b/containers/libreportal/frontend/css/topbar.css
@@ -3,10 +3,10 @@
/* Topbar layout, nav pills, donate/logout buttons. Extracted from style.css. Theme via var(--*) tokens. */
/* Developer-mode strip — sits flush under the fixed topbar when CFG_DEV_MODE
- is on. Amber-tinted glass so it reads as "non-default state" without
- shouting. Body gets .has-dev-banner to bump padding-top by the strip's
- height; dismissal is local and remembered in localStorage until dev
- mode is toggled off + on again. */
+ is on. Neutral glass so it reads as "system bar" not "warning"; only the
+ icon picks up the theme accent. Body gets .has-dev-banner to bump
+ padding-top by the strip's height; dismissal is local and remembered in
+ localStorage until dev mode is toggled off + on again. */
.dev-banner {
position: fixed;
top: 60px;
@@ -16,13 +16,13 @@
height: 36px;
display: flex;
align-items: center;
- justify-content: space-between;
- padding: 0 24px;
+ justify-content: center;
+ padding: 0 56px 0 24px;
font-size: 0.85rem;
font-weight: 500;
color: var(--text-primary);
- background: rgba(var(--status-warning-rgb), 0.14);
- border-bottom: 1px solid rgba(var(--status-warning-rgb), 0.35);
+ background: rgba(var(--text-rgb), 0.04);
+ border-bottom: 1px solid rgba(var(--text-rgb), 0.12);
backdrop-filter: blur(12px) saturate(140%);
-webkit-backdrop-filter: blur(12px) saturate(140%);
}
@@ -33,10 +33,15 @@
display: inline-flex;
align-items: center;
gap: 8px;
- color: var(--status-warning);
}
+.dev-banner-label svg { color: var(--accent); }
+
.dev-banner-close {
+ position: absolute;
+ right: 12px;
+ top: 50%;
+ transform: translateY(-50%);
display: inline-flex;
align-items: center;
justify-content: center;
@@ -47,7 +52,7 @@
border: none;
border-radius: 6px;
color: var(--text-primary);
- opacity: 0.7;
+ opacity: 0.65;
cursor: pointer;
transition: opacity 0.15s ease, background 0.15s ease;
}
@@ -60,7 +65,7 @@
body.has-dev-banner { padding-top: 96px; }
@media (max-width: 768px) {
- .dev-banner { padding: 0 12px; font-size: 0.8rem; }
+ .dev-banner { padding: 0 48px 0 12px; font-size: 0.8rem; }
body.has-dev-banner .mobile-drawer { top: 96px; height: calc(100vh - 96px); }
}
diff --git a/containers/libreportal/frontend/js/components/task/task-actions.js b/containers/libreportal/frontend/js/components/task/task-actions.js
index 33c1616..ff89376 100755
--- a/containers/libreportal/frontend/js/components/task/task-actions.js
+++ b/containers/libreportal/frontend/js/components/task/task-actions.js
@@ -315,9 +315,12 @@ async configUpdate(changes) {
? window.tasksManager.getTaskTypeIcon({ type: action })
: null)?.icon || '';
const customIcon = typeIcon ? `${typeIcon}` : null;
+ const friendly = (this.tasksManager && typeof this.tasksManager.formatActionTitle === 'function')
+ ? this.tasksManager.formatActionTitle(action)
+ : (action.charAt(0).toUpperCase() + action.slice(1));
const headline = displayLabel
? `${displayLabel} task started!`
- : `${action.charAt(0).toUpperCase() + action.slice(1)} task started!`;
+ : `${friendly} task started!`;
window.notificationSystem.show(
`${displayName}
${headline}`,
'success',
diff --git a/containers/libreportal/frontend/js/components/tasks/tasks-manager.js b/containers/libreportal/frontend/js/components/tasks/tasks-manager.js
index 85bdd3d..bb8f00f 100755
--- a/containers/libreportal/frontend/js/components/tasks/tasks-manager.js
+++ b/containers/libreportal/frontend/js/components/tasks/tasks-manager.js
@@ -51,10 +51,33 @@ class TasksManager {
// Setup mobile menu
this.setupMobileMenu();
-
+
//// // console.log('✅ TasksManager initialized with modular architecture');
}
+ // User-facing label for a task action. Explicit map first (so
+ // 'config_update' reads as 'Update Config', not 'Config Update');
+ // anything not listed falls back to snake/kebab → Title Case so a
+ // future task type still renders cleanly instead of leaking the
+ // literal id like "Config_update".
+ formatActionTitle(action) {
+ if (!action) return 'Task';
+ const map = {
+ 'install': 'Install', 'app-install': 'Install',
+ 'uninstall': 'Uninstall', 'restart': 'Restart',
+ 'start': 'Start', 'stop': 'Stop',
+ 'update': 'Update', 'rebuild': 'Rebuild',
+ 'backup': 'Backup', 'restore': 'Restore',
+ 'delete': 'Delete Backup', 'delete_all': 'Delete All Backups',
+ 'config_update': 'Update Config', 'update_config': 'Update Config',
+ 'system_update': 'Update System',
+ 'setup-config': 'Apply Configuration',
+ 'setup-finalize': 'Finalize Setup'
+ };
+ if (map[action]) return map[action];
+ return action.split(/[_-]/).map(w => w ? w.charAt(0).toUpperCase() + w.slice(1) : '').join(' ');
+ }
+
// Initialize task system after scripts are loaded
initializeTaskSystem() {
try {
@@ -1381,17 +1404,7 @@ class TasksManager {
if (window.notificationSystem && task) {
const appName = task.app || null;
const action = task.type || 'task';
- const friendlyActionMap = {
- 'install': 'Install', 'app-install': 'Install',
- 'uninstall': 'Uninstall', 'restart': 'Restart',
- 'start': 'Start', 'stop': 'Stop',
- 'update': 'Update', 'rebuild': 'Rebuild',
- 'backup': 'Backup', 'restore': 'Restore',
- 'delete': 'Delete Backup', 'delete_all': 'Delete All Backups',
- 'setup-config': 'Apply Configuration',
- 'setup-finalize': 'Finalize Setup'
- };
- let actionTitle = friendlyActionMap[action] || (action.charAt(0).toUpperCase() + action.slice(1));
+ 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.