summaryrefslogtreecommitdiff
path: root/makima/frontend/src/components/mesh/TaskDetail.tsx
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-18 18:02:08 +0000
committerGitHub <noreply@github.com>2026-01-18 18:02:08 +0000
commite0da93a20a965125ba4cbb46e3e0e179f06c2a08 (patch)
tree5d127394e1dfa921c5d09fe8f10d716f6548d168 /makima/frontend/src/components/mesh/TaskDetail.tsx
parent869f21ee2efaefed6a5aa4fbd417c25df8dec02a (diff)
downloadsoryu-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.tsx43
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;