fix(webui/tasks): auto-expand opens one row, not all of them

autoExpandTask (the monitorTask path) opened its row directly without
collapsing the others and never set highlightedTaskId — unlike every
other opener (toggleTaskDetails, selectTask), which enforce a single
open row. So a burst of monitored task creations, e.g. a multi-app
first install, stacked every panel open at once.

Wait for the row to render, then delegate to selectTask, which collapses
any other open panel, sets highlightedTaskId, attaches the right log
view (live stream vs snapshot) and scrolls into view. Setting
highlightedTaskId also makes monitorTask's own guard trip after the
first task, so the running-task auto-follow takes over from there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
librelad 2026-06-22 14:41:36 +01:00
parent 38a7e4c365
commit 70f16ef1e3

View File

@ -197,63 +197,29 @@ Object.assign(TasksManager.prototype, {
window.removeEventListener('taskCompleted', onComplete); window.removeEventListener('taskCompleted', onComplete);
}); });
}, },
// Auto-expand a task when it's created // Auto-expand a task when it's created/started. Waits for its row to land in
async autoExpandTask(taskId) { // the DOM, then hands off to selectTask, which collapses any other open panel
// first. Opening the row directly here (as this used to) skipped that
// Wait for task to be rendered // collapse and never set highlightedTaskId, so a burst of monitored tasks —
// e.g. a multi-app first install — stacked every panel open instead of
// showing just the active one.
autoExpandTask(taskId) {
let attempts = 0; let attempts = 0;
const maxAttempts = 10; const maxAttempts = 10;
const tryExpand = async () => { const tryExpand = () => {
attempts++; attempts++;
// selectTask returns false until the row exists; once it succeeds it has
// Check if task element exists // also attached the right log view (live stream vs snapshot), set
const taskElement = document.querySelector(`[data-task-id="${taskId}"]`); // highlightedTaskId and scrolled the row into view — nothing more to do.
if (!taskElement) { if (this.selectTask(taskId)) return;
if (attempts < maxAttempts) { if (attempts < maxAttempts) {
setTimeout(tryExpand, 500); // Try again in 500ms setTimeout(tryExpand, 500);
} else { } else {
console.warn(`⚠️ Could not find task element for ${taskId} after ${maxAttempts} attempts`); console.warn(`⚠️ Could not find task element for ${taskId} after ${maxAttempts} attempts`);
}
return;
} }
// Get the details element
const details = document.getElementById(`details-${taskId}`);
if (!details) {
if (attempts < maxAttempts) {
setTimeout(tryExpand, 500);
} else {
console.warn(`⚠️ Could not find details element for ${taskId}`);
}
return;
}
// Expand the task details
details.style.display = 'block';
details.classList.add('task-details-open');
// Update toggle button
const toggleBtn = document.querySelector(`.task-btn.toggle-details[onclick*="toggleTaskDetails('${taskId}')"]`);
if (toggleBtn) {
toggleBtn.classList.add('expanded');
}
// Scroll to the task
taskElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
// Load the output if task is completed
const task = await this.taskManager.getTask(taskId);
if (task && (task.status === 'completed' || task.status === 'failed')) {
setTimeout(() => {
this.loadTaskOutput(taskId);
}, 1000);
}
}; };
tryExpand(); tryExpand();
}, },
}); });