diff options
| author | soryu <soryu@soryu.co> | 2026-01-18 18:02:08 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-18 18:02:08 +0000 |
| commit | e0da93a20a965125ba4cbb46e3e0e179f06c2a08 (patch) | |
| tree | 5d127394e1dfa921c5d09fe8f10d716f6548d168 /makima/frontend/src/components/mesh/TaskDetail.tsx | |
| parent | 869f21ee2efaefed6a5aa4fbd417c25df8dec02a (diff) | |
| download | soryu-e0da93a20a965125ba4cbb46e3e0e179f06c2a08.tar.gz soryu-e0da93a20a965125ba4cbb46e3e0e179f06c2a08.zip | |
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 <noreply@anthropic.com>
* 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 <noreply@anthropic.com>
* Task completion checkpoint
* Task completion checkpoint
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/frontend/src/components/mesh/TaskDetail.tsx')
| -rw-r--r-- | makima/frontend/src/components/mesh/TaskDetail.tsx | 43 |
1 files changed, 27 insertions, 16 deletions
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<void>; onAutoMerge?: () => Promise<void>; fetchSubtasks?: (taskId: string) => Promise<TaskSummary[]>; + /** 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({ </div> )} - {/* Subtasks */} + {/* Subtasks / Contract Tasks (for supervisors) */} <div className="space-y-2"> <div className="flex items-center justify-between"> <div className="flex items-center gap-3"> <div className="font-mono text-xs text-[#9bc3ff] tracking-wide uppercase"> - Subtasks ({task.subtasks.length}) + {isSupervisor ? `Contract Tasks (${displayTasks.length})` : `Subtasks (${displayTasks.length})`} </div> - {task.subtasks.length > 0 && ( + {displayTasks.length > 0 && ( <button onClick={() => setUseTreeView(!useTreeView)} className="font-mono text-[9px] text-[#555] hover:text-[#75aafc]" @@ -661,41 +672,41 @@ export function TaskDetail({ </button> )} </div> - {/* 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 ? ( <button onClick={onCreateSubtask} className="px-2 py-1 font-mono text-[10px] text-[#9bc3ff] border border-[rgba(117,170,252,0.25)] hover:border-[#3f6fb3] transition-colors uppercase" > + Add Subtask </button> - ) : ( + ) : !isSupervisor ? ( <span className="px-2 py-1 font-mono text-[10px] text-[#555] border border-[#333]" title="Maximum depth reached"> Max depth </span> - )} + ) : null} </div> - {/* Progress bar for subtasks */} - {task.subtasks.length > 0 && ( + {/* Progress bar for tasks */} + {displayTasks.length > 0 && ( <SubtaskProgressBar stats={subtaskStats} /> )} - {task.subtasks.length === 0 ? ( + {displayTasks.length === 0 ? ( <div className="text-[#555] font-mono text-xs py-4 text-center"> - No subtasks yet + {isSupervisor ? "No tasks in contract yet" : "No subtasks yet"} </div> ) : useTreeView ? ( <div className="border border-[rgba(117,170,252,0.15)]"> <SubtaskTree - subtasks={task.subtasks} + subtasks={displayTasks} onSelect={onSelectSubtask} fetchSubtasks={fetchSubtasks} /> </div> ) : ( <div className="divide-y divide-[rgba(117,170,252,0.15)] border border-[rgba(117,170,252,0.15)]"> - {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; |
