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/routes | |
| 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/routes')
| -rw-r--r-- | makima/frontend/src/routes/mesh.tsx | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/makima/frontend/src/routes/mesh.tsx b/makima/frontend/src/routes/mesh.tsx index cc09bca..a8d3574 100644 --- a/makima/frontend/src/routes/mesh.tsx +++ b/makima/frontend/src/routes/mesh.tsx @@ -7,7 +7,7 @@ import { TaskOutput } from "../components/mesh/TaskOutput"; import { UnifiedMeshChatInput } from "../components/mesh/UnifiedMeshChatInput"; import { useTasks } from "../hooks/useTasks"; import { useTaskSubscription, type TaskUpdateEvent, type TaskOutputEvent } from "../hooks/useTaskSubscription"; -import type { TaskWithSubtasks, MeshChatContext, ContractSummary, ContractWithRelations, DaemonDirectory } from "../lib/api"; +import type { TaskWithSubtasks, MeshChatContext, ContractSummary, ContractWithRelations, DaemonDirectory, TaskSummary } from "../lib/api"; import { startTask as startTaskApi, stopTask as stopTaskApi, getTaskOutput, listContracts, getContract, getDaemonDirectories, continueTask as continueTaskApi, resumeSupervisor } from "../lib/api"; import { DirectoryInput } from "../components/mesh/DirectoryInput"; import { useAuth } from "../contexts/AuthContext"; @@ -119,6 +119,8 @@ export default function MeshPage() { // Track which subtask's output we're viewing (null = parent task) const [viewingSubtaskId, setViewingSubtaskId] = useState<string | null>(null); const [viewingSubtaskName, setViewingSubtaskName] = useState<string | null>(null); + // For supervisor tasks: all tasks in the contract (excluding the supervisor itself) + const [contractTasks, setContractTasks] = useState<TaskSummary[]>([]); // View mode for the split panel layout const [viewMode, setViewMode] = useState<ViewMode>("split"); // Width of the task panel as a percentage (0-100) @@ -309,6 +311,26 @@ export default function MeshPage() { } }, [id, fetchTask]); + // For supervisor tasks: fetch all tasks in the contract (excluding the supervisor itself) + useEffect(() => { + if (taskDetail?.isSupervisor && taskDetail.contractId) { + getContract(taskDetail.contractId) + .then((contract) => { + // Filter out the supervisor task itself + const tasksExcludingSupervisor = contract.tasks.filter( + (t) => t.id !== taskDetail.id + ); + setContractTasks(tasksExcludingSupervisor); + }) + .catch((err) => { + console.error("Failed to fetch contract tasks for supervisor:", err); + setContractTasks([]); + }); + } else { + setContractTasks([]); + } + }, [taskDetail?.isSupervisor, taskDetail?.contractId, taskDetail?.id]); + const handleSelectTask = useCallback( (taskId: string) => { navigate(`/mesh/${taskId}`); @@ -711,6 +733,7 @@ export default function MeshPage() { onToggleSubtaskOutput={handleToggleSubtaskOutput} viewingSubtaskId={viewingSubtaskId} onViewContract={(contractId) => navigate(`/contracts/${contractId}`)} + contractTasks={taskDetail.isSupervisor ? contractTasks : undefined} /> </div> )} |
