diff --git a/frontend/src/pages/task-details.tsx b/frontend/src/pages/task-details.tsx index d391c424..dcb6e370 100644 --- a/frontend/src/pages/task-details.tsx +++ b/frontend/src/pages/task-details.tsx @@ -56,6 +56,7 @@ export function TaskDetailsPage() { const [taskLoading, setTaskLoading] = useState(true); const [taskAttempts, setTaskAttempts] = useState([]); const [taskAttemptsLoading, setTaskAttemptsLoading] = useState(false); + const [taskAttemptsInitialLoad, setTaskAttemptsInitialLoad] = useState(true); const [selectedAttempt, setSelectedAttempt] = useState( null ); @@ -75,9 +76,26 @@ export function TaskDetailsPage() { const [editedStatus, setEditedStatus] = useState("todo"); const [savingTask, setSavingTask] = useState(false); - // Check if the selected attempt is currently running (latest activity is "inprogress") - const isAttemptRunning = selectedAttempt && attemptActivities.length > 0 && - attemptActivities[0].status === "inprogress"; + // Check if the selected attempt is currently running (latest activity is "inprogress" or "init") + const isAttemptRunning = + selectedAttempt && + attemptActivities.length > 0 && + (attemptActivities[0].status === "inprogress" || + attemptActivities[0].status === "init"); + + // Polling for updates when attempt is running + useEffect(() => { + if (!isAttemptRunning || !task) return; + + const interval = setInterval(() => { + fetchTaskAttempts(task.id, true); // Background update + if (selectedAttempt) { + fetchAttemptActivities(selectedAttempt.id, true); // Background update + } + }, 2000); + + return () => clearInterval(interval); + }, [isAttemptRunning, task?.id, selectedAttempt?.id]); useEffect(() => { if (projectId && taskId) { @@ -122,11 +140,18 @@ export function TaskDetailsPage() { } }; - const fetchTaskAttempts = async (taskId: string) => { + const fetchTaskAttempts = async ( + taskId: string, + isBackgroundUpdate = false + ) => { if (!projectId) return; try { - setTaskAttemptsLoading(true); + // Show loading for user-initiated actions, not background polling + if (!isBackgroundUpdate) { + setTaskAttemptsLoading(true); + } + const response = await makeAuthenticatedRequest( `/api/projects/${projectId}/tasks/${taskId}/attempts` ); @@ -135,8 +160,21 @@ export function TaskDetailsPage() { const result: ApiResponse = await response.json(); if (result.success && result.data) { setTaskAttempts(result.data); - // Automatically select the latest attempt if available - if (result.data.length > 0) { + setTaskAttemptsInitialLoad(false); + + // For background updates, preserve the selected attempt + if (isBackgroundUpdate && selectedAttempt) { + const updatedAttempt = result.data.find( + (a) => a.id === selectedAttempt.id + ); + if (updatedAttempt) { + setSelectedAttempt(updatedAttempt); + return; + } + } + + // Auto-select latest attempt for initial loads + if (result.data.length > 0 && !isBackgroundUpdate) { const latestAttempt = result.data.reduce((latest, current) => new Date(current.created_at) > new Date(latest.created_at) ? current @@ -152,15 +190,21 @@ export function TaskDetailsPage() { } catch (err) { setError("Failed to load task attempts"); } finally { - setTaskAttemptsLoading(false); + if (!isBackgroundUpdate) { + setTaskAttemptsLoading(false); + } } }; - const fetchAttemptActivities = async (attemptId: string) => { + const fetchAttemptActivities = async (attemptId: string, isBackgroundUpdate = false) => { if (!task || !projectId) return; try { - setActivitiesLoading(true); + // Only show loading for user-initiated actions, not background polling + if (!isBackgroundUpdate) { + setActivitiesLoading(true); + } + const response = await makeAuthenticatedRequest( `/api/projects/${projectId}/tasks/${task.id}/attempts/${attemptId}/activities` ); @@ -177,7 +221,9 @@ export function TaskDetailsPage() { } catch (err) { setError("Failed to load attempt activities"); } finally { - setActivitiesLoading(false); + if (!isBackgroundUpdate) { + setActivitiesLoading(false); + } } }; @@ -357,11 +403,7 @@ export function TaskDetailsPage() {
{isEditMode ? ( <> -
@@ -500,9 +540,7 @@ export function TaskDetailsPage() { To Do - - In Progress - + In Progress In Review Done Cancelled @@ -568,7 +606,7 @@ export function TaskDetailsPage() { - {taskAttemptsLoading ? ( + {taskAttemptsInitialLoad && taskAttemptsLoading ? (
Loading...
@@ -674,9 +712,7 @@ export function TaskDetailsPage() { {selectedAttempt.worktree_path}

{activitiesLoading ? ( -
- Loading activities... -
+
Loading activities...
) : attemptActivities.length === 0 ? (
No activities found