From e0da93a20a965125ba4cbb46e3e0e179f06c2a08 Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 18 Jan 2026 18:02:08 +0000 Subject: Improve Mesh Tab: Organize by contract with status filter (#5) * Add status filter toggle to Mesh Tab TaskList component Add a filter toggle at the top of the TaskList that allows filtering by contract status (All, Active, Completed, Archive) with Active as the default. Changes: - Backend: Add contract_status field to TaskSummary struct in models.rs - Backend: Update all SQL queries returning TaskSummary to include c.status as contract_status from the contracts table join - Frontend: Add contractStatus to TaskSummary TypeScript type - Frontend: Add useState for statusFilter with 'active' as default - Frontend: Add filter button group in header area next to '+ New Task' - Frontend: Update groupedTasks useMemo to filter based on contract status - Frontend: Update empty state message to reflect current filter Co-Authored-By: Claude Opus 4.5 * Task completion checkpoint * feat(mesh): show all contract tasks for supervisor tasks When viewing a supervisor task (task.isSupervisor === true), the TaskDetail component now shows all tasks in the contract instead of showing the subtasks tree. Changes: - Add contractTasks prop to TaskDetailProps for passing contract tasks - Add displayTasks computed value that uses contractTasks for supervisors - Change section header from "Subtasks" to "Contract Tasks" for supervisors - Hide the "+ Add Subtask" button for supervisor tasks - Update empty state message for supervisors - Fetch contract tasks in mesh.tsx when viewing a supervisor task - Filter out the supervisor itself from the contract tasks list Co-Authored-By: Claude Opus 4.5 * Task completion checkpoint * Task completion checkpoint --------- Co-authored-by: Claude Opus 4.5 --- makima/frontend/src/components/mesh/TaskDetail.tsx | 43 ++++++++++++++-------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'makima/frontend/src/components/mesh/TaskDetail.tsx') diff --git a/makima/frontend/src/components/mesh/TaskDetail.tsx b/makima/frontend/src/components/mesh/TaskDetail.tsx index 8e853e7..efe26a8 100644 --- a/makima/frontend/src/components/mesh/TaskDetail.tsx +++ b/makima/frontend/src/components/mesh/TaskDetail.tsx @@ -32,6 +32,8 @@ interface TaskDetailProps { onCreatePR?: (title: string, body: string, draft: boolean) => Promise; onAutoMerge?: () => Promise; fetchSubtasks?: (taskId: string) => Promise; + /** For supervisor tasks: all tasks in the contract (excluding the supervisor itself) */ + contractTasks?: TaskSummary[]; } function formatDate(dateStr: string): string { @@ -114,6 +116,7 @@ export function TaskDetail({ onCreatePR, onAutoMerge, fetchSubtasks, + contractTasks, }: TaskDetailProps) { const [isEditing, setIsEditing] = useState(false); const [editName, setEditName] = useState(task.name); @@ -149,10 +152,18 @@ export function TaskDetail({ // Show continue for supervisors (always) or terminal states for other tasks const canContinue = isSupervisor || isTaskTerminal; - // Calculate subtask statistics + // Determine which tasks to show: for supervisors, show contractTasks; for regular tasks, show subtasks + const displayTasks = useMemo(() => { + if (isSupervisor && contractTasks) { + return contractTasks; + } + return task.subtasks; + }, [isSupervisor, contractTasks, task.subtasks]); + + // Calculate task statistics for progress bar const subtaskStats = useMemo( - () => calculateTreeStats(task.subtasks), - [task.subtasks] + () => calculateTreeStats(displayTasks), + [displayTasks] ); // Check if task can create PR @@ -645,14 +656,14 @@ export function TaskDetail({ )} - {/* Subtasks */} + {/* Subtasks / Contract Tasks (for supervisors) */}
- Subtasks ({task.subtasks.length}) + {isSupervisor ? `Contract Tasks (${displayTasks.length})` : `Subtasks (${displayTasks.length})`}
- {task.subtasks.length > 0 && ( + {displayTasks.length > 0 && ( )}
- {/* Disable adding subtasks at max depth (2 = sub-subtask, cannot have children) */} - {task.depth < 2 ? ( + {/* Disable adding subtasks for supervisors and at max depth (2 = sub-subtask, cannot have children) */} + {!isSupervisor && task.depth < 2 ? ( - ) : ( + ) : !isSupervisor ? ( Max depth - )} + ) : null}
- {/* Progress bar for subtasks */} - {task.subtasks.length > 0 && ( + {/* Progress bar for tasks */} + {displayTasks.length > 0 && ( )} - {task.subtasks.length === 0 ? ( + {displayTasks.length === 0 ? (
- No subtasks yet + {isSupervisor ? "No tasks in contract yet" : "No subtasks yet"}
) : useTreeView ? (
) : (
- {task.subtasks.map((subtask: TaskSummary) => { + {displayTasks.map((subtask: TaskSummary) => { const isRunning = subtask.status === "running" || subtask.status === "initializing" || subtask.status === "starting"; const isViewingOutput = viewingSubtaskId === subtask.id; const isExpanded = expandedSubtaskId === subtask.id; -- cgit v1.2.3