diff options
| author | soryu <soryu@soryu.co> | 2026-01-21 16:19:22 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-21 16:19:22 +0000 |
| commit | f07f5f6bb2691cb62b0406a912e1d4962abee8d8 (patch) | |
| tree | 823d5f33359252d6792ec1d96b75b69e00bd9189 | |
| parent | ef839683aed1f501e0de507e2ca72ccdc7b29666 (diff) | |
| download | soryu-f07f5f6bb2691cb62b0406a912e1d4962abee8d8.tar.gz soryu-f07f5f6bb2691cb62b0406a912e1d4962abee8d8.zip | |
feat(frontend): Add branch button and modal to TaskDetail
- Import BranchTaskModal component
- Add onBranch prop to TaskDetailProps interface
- Add showBranchModal state
- Add canBranch check (task status !== "pending")
- Add purple-themed Branch button next to Continue button
- Render BranchTaskModal when showBranchModal is true
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
| -rw-r--r-- | makima/frontend/src/components/mesh/TaskDetail.tsx | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/makima/frontend/src/components/mesh/TaskDetail.tsx b/makima/frontend/src/components/mesh/TaskDetail.tsx index efe26a8..a74f394 100644 --- a/makima/frontend/src/components/mesh/TaskDetail.tsx +++ b/makima/frontend/src/components/mesh/TaskDetail.tsx @@ -6,6 +6,7 @@ import { OverlayDiffViewer } from "./OverlayDiffViewer"; import { PRPreview } from "./PRPreview"; import { InlineSubtaskEditor } from "./InlineSubtaskEditor"; import { DirectoryInput } from "./DirectoryInput"; +import { BranchTaskModal } from "./BranchTaskModal"; interface TaskDetailProps { task: TaskWithSubtasks; @@ -25,6 +26,8 @@ interface TaskDetailProps { viewingSubtaskId?: string | null; /** Navigate to view the contract */ onViewContract?: (contractId: string) => void; + /** Branch the task to create a new task with same state */ + onBranch?: (taskId: string, message: string, name?: string) => Promise<void>; // Optional advanced features overlayDiff?: string; changedFiles?: string[]; @@ -110,6 +113,7 @@ export function TaskDetail({ onToggleSubtaskOutput, viewingSubtaskId, onViewContract, + onBranch, overlayDiff, changedFiles, onRequestDiff, @@ -142,6 +146,8 @@ export function TaskDetail({ const [isCloning, setIsCloning] = useState(false); const [cloneError, setCloneError] = useState<string | null>(null); const [cloneTargetDir, setCloneTargetDir] = useState(""); + // Track branch modal state + const [showBranchModal, setShowBranchModal] = useState(false); // Check if task is running const isTaskRunning = task.status === "running" || task.status === "initializing" || task.status === "starting"; @@ -151,6 +157,8 @@ export function TaskDetail({ const isSupervisor = task.isSupervisor === true; // Show continue for supervisors (always) or terminal states for other tasks const canContinue = isSupervisor || isTaskTerminal; + // Show branch button when task has run at least once (not pending) + const canBranch = onBranch && task.status !== "pending"; // Determine which tasks to show: for supervisors, show contractTasks; for regular tasks, show subtasks const displayTasks = useMemo(() => { @@ -380,6 +388,15 @@ export function TaskDetail({ Continue </button> )} + {canBranch && ( + <button + onClick={() => setShowBranchModal(true)} + className="px-3 py-1 font-mono text-xs text-purple-400 border border-purple-400/30 hover:border-purple-400/50 hover:bg-purple-400/10 transition-colors uppercase flex items-center gap-1" + > + <span className="w-1.5 h-1.5 bg-purple-400 rounded-full" /> + Branch + </button> + )} <button onClick={() => setIsEditing(true)} className="px-3 py-1 font-mono text-xs text-[#9bc3ff] border border-[rgba(117,170,252,0.25)] hover:border-[#3f6fb3] transition-colors uppercase" @@ -908,6 +925,15 @@ export function TaskDetail({ </div> </div> )} + + {/* Branch Task Modal */} + {showBranchModal && onBranch && ( + <BranchTaskModal + task={task} + onBranch={onBranch} + onClose={() => setShowBranchModal(false)} + /> + )} </div> ); } |
