diff --git a/apps/app/src/components/ui/task-progress-panel.tsx b/apps/app/src/components/ui/task-progress-panel.tsx index 6ab8f35d..4430e5e3 100644 --- a/apps/app/src/components/ui/task-progress-panel.tsx +++ b/apps/app/src/components/ui/task-progress-panel.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import { cn } from "@/lib/utils"; import { CheckCircle2, Circle, Loader2, ChevronDown, ChevronRight } from "lucide-react"; import { getElectronAPI } from "@/lib/electron"; @@ -16,15 +16,65 @@ interface TaskInfo { interface TaskProgressPanelProps { featureId: string; + projectPath?: string; className?: string; } -export function TaskProgressPanel({ featureId, className }: TaskProgressPanelProps) { +export function TaskProgressPanel({ featureId, projectPath, className }: TaskProgressPanelProps) { const [tasks, setTasks] = useState([]); const [isExpanded, setIsExpanded] = useState(true); const [currentTaskId, setCurrentTaskId] = useState(null); + const [isLoading, setIsLoading] = useState(true); - // Listen to task events + // Load initial tasks from feature's planSpec + const loadInitialTasks = useCallback(async () => { + if (!projectPath) { + setIsLoading(false); + return; + } + + try { + const api = getElectronAPI(); + if (!api?.features) { + setIsLoading(false); + return; + } + + const result = await api.features.get(projectPath, featureId); + if (result.success && result.feature?.planSpec?.tasks) { + const planTasks = result.feature.planSpec.tasks; + const currentId = result.feature.planSpec.currentTaskId; + const completedCount = result.feature.planSpec.tasksCompleted || 0; + + // Convert planSpec tasks to TaskInfo with proper status + const initialTasks: TaskInfo[] = planTasks.map((t: any, index: number) => ({ + id: t.id, + description: t.description, + filePath: t.filePath, + phase: t.phase, + status: index < completedCount + ? "completed" as const + : t.id === currentId + ? "in_progress" as const + : "pending" as const, + })); + + setTasks(initialTasks); + setCurrentTaskId(currentId || null); + } + } catch (error) { + console.error("Failed to load initial tasks:", error); + } finally { + setIsLoading(false); + } + }, [featureId, projectPath]); + + // Load initial state on mount + useEffect(() => { + loadInitialTasks(); + }, [loadInitialTasks]); + + // Listen to task events for real-time updates useEffect(() => { const api = getElectronAPI(); if (!api?.autoMode) return; @@ -69,24 +119,25 @@ export function TaskProgressPanel({ featureId, className }: TaskProgressPanelPro t.id === taskEvent.taskId ? { ...t, status: "completed" as const } : t ) ); - // Clear current task if it was completed - if (currentTaskId === taskEvent.taskId) { - setCurrentTaskId(null); - } + setCurrentTaskId(null); } break; } }); return unsubscribe; - }, [featureId, currentTaskId]); + }, [featureId]); // Calculate progress const completedCount = tasks.filter((t) => t.status === "completed").length; const totalCount = tasks.length; const progressPercent = totalCount > 0 ? Math.round((completedCount / totalCount) * 100) : 0; - // Don't render if no tasks + // Don't render if loading or no tasks + if (isLoading) { + return null; + } + if (tasks.length === 0) { return null; } diff --git a/apps/app/src/components/views/board-view/dialogs/agent-output-modal.tsx b/apps/app/src/components/views/board-view/dialogs/agent-output-modal.tsx index fd0dbea4..c968445b 100644 --- a/apps/app/src/components/views/board-view/dialogs/agent-output-modal.tsx +++ b/apps/app/src/components/views/board-view/dialogs/agent-output-modal.tsx @@ -218,6 +218,13 @@ export function AgentOutputModal({ // Show when plan is auto-approved newContent = `\nāœ… Plan auto-approved - continuing to implementation...\n`; break; + case "plan_revision_requested": + // Show when user requests plan revision + if ("planVersion" in event) { + const revisionEvent = event as Extract; + newContent = `\nšŸ”„ Revising plan based on your feedback (v${revisionEvent.planVersion})...\n`; + } + break; case "auto_mode_task_started": // Show when a task starts if ("taskId" in event && "taskDescription" in event) { @@ -362,7 +369,11 @@ export function AgentOutputModal({ {/* Task Progress Panel - shows when tasks are being executed */} - + {viewMode === "changes" ? (
diff --git a/apps/app/src/components/views/board-view/dialogs/plan-approval-dialog.tsx b/apps/app/src/components/views/board-view/dialogs/plan-approval-dialog.tsx index dd2f22ac..ff710105 100644 --- a/apps/app/src/components/views/board-view/dialogs/plan-approval-dialog.tsx +++ b/apps/app/src/components/views/board-view/dialogs/plan-approval-dialog.tsx @@ -14,7 +14,7 @@ import { Textarea } from "@/components/ui/textarea"; import { Markdown } from "@/components/ui/markdown"; import { Label } from "@/components/ui/label"; import { Feature } from "@/store/app-store"; -import { Check, X, Edit2, Eye, Loader2 } from "lucide-react"; +import { Check, RefreshCw, Edit2, Eye, Loader2 } from "lucide-react"; interface PlanApprovalDialogProps { open: boolean; @@ -143,18 +143,21 @@ export function PlanApprovalDialog({ )}
- {/* Reject Feedback Section - Only show when not in viewOnly mode */} + {/* Revision Feedback Section - Only show when not in viewOnly mode */} {showRejectFeedback && !viewOnly && (
- +