diff --git a/ui/suite/tasks/tasks.js b/ui/suite/tasks/tasks.js index aeac7aa..3c7fcdd 100644 --- a/ui/suite/tasks/tasks.js +++ b/ui/suite/tasks/tasks.js @@ -334,16 +334,33 @@ function handleWebSocketMessage(data) { case "task_completed": console.log("[Tasks WS] TASK_COMPLETED:", data.message); addAgentLog("success", `[COMPLETE] ${data.message}`); + + // Extract app_url from details if present + let appUrl = null; + if (data.details && data.details.startsWith("app_url:")) { + appUrl = data.details.substring(8); + addAgentLog("success", `🚀 App URL: ${appUrl}`); + showAppUrlNotification(appUrl); + } + if (data.activity) { updateActivityMetrics(data.activity); logFinalStats(data.activity); } - completeFloatingProgress(data.message, data.activity); + completeFloatingProgress(data.message, data.activity, appUrl); updateProgressUI(data); - onTaskCompleted(data); + onTaskCompleted(data, appUrl); + + // Play completion sound + playCompletionSound(); + + // Refresh task list and details if (typeof htmx !== "undefined") { htmx.trigger(document.body, "taskCreated"); } + if (data.task_id && data.task_id === TasksState.selectedTaskId) { + loadTaskDetails(data.task_id); + } break; case "task_error": @@ -588,7 +605,7 @@ function updateFloatingProgressBar( } } -function completeFloatingProgress(message, activity) { +function completeFloatingProgress(message, activity, appUrl) { const fillEl = document.getElementById("floating-progress-fill"); if (fillEl) fillEl.style.width = "100%"; @@ -1188,10 +1205,120 @@ function showDetailedView(taskId) { // TASK LIFECYCLE // ============================================================================= -function onTaskCompleted(task) { - showToast(`Task completed: ${task.title}`, "success"); - addAgentLog("success", `[COMPLETE] Task #${task.id}: ${task.title}`); - updateTaskCard(task); +function onTaskCompleted(data, appUrl) { + const title = data.title || data.message || "Task"; + const taskId = data.task_id || data.id; + + if (appUrl) { + showToast(`App ready! Click to open: ${appUrl}`, "success", 10000, () => { + window.open(appUrl, "_blank"); + }); + addAgentLog("success", `[COMPLETE] Task #${taskId}: ${title}`); + addAgentLog("success", `[URL] ${appUrl}`); + } else { + showToast(`Task completed: ${title}`, "success"); + addAgentLog("success", `[COMPLETE] Task #${taskId}: ${title}`); + } + + if (data.task) { + updateTaskCard(data.task); + } +} + +function showAppUrlNotification(appUrl) { + // Create a prominent notification for the app URL + let notification = document.getElementById("app-url-notification"); + if (!notification) { + notification = document.createElement("div"); + notification.id = "app-url-notification"; + notification.style.cssText = ` + position: fixed; + top: 80px; + right: 24px; + background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%); + color: white; + padding: 16px 24px; + border-radius: 12px; + box-shadow: 0 8px 32px rgba(34, 197, 94, 0.4); + z-index: 10001; + max-width: 400px; + animation: slideInRight 0.5s ease; + `; + document.body.appendChild(notification); + } + + notification.innerHTML = ` +