diff --git a/frontend/src/components/session/BranchNode.tsx b/frontend/src/components/session/BranchNode.tsx index aec82f56..4d78a015 100644 --- a/frontend/src/components/session/BranchNode.tsx +++ b/frontend/src/components/session/BranchNode.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react' import { CircleDot, CheckCircle2, XCircle, Circle, RotateCcw } from 'lucide-react' import { cn } from '@/lib/utils' import type { BranchResponse } from '@/types/branching' @@ -52,40 +53,86 @@ interface BranchNodeProps { } export function BranchNode({ branch, depth, isActive, onClick }: BranchNodeProps) { + const [isHovered, setIsHovered] = useState(false) const config = STATUS_CONFIG[branch.status] const Icon = config.icon + const showDetail = isActive || isHovered return ( - + + {/* Expandable detail panel */} +
- {config.label} - - +
+ {branch.context_summary ? ( + <> + {branch.context_summary.tried.length > 0 && ( +

+ Tried:{' '} + {branch.context_summary.tried.join(', ')} +

+ )} + {branch.context_summary.concluded && ( +

+ Result:{' '} + {branch.context_summary.concluded} +

+ )} + + ) : ( +

No activity yet

+ )} + {branch.status_reason && ( +

+ Reason:{' '} + {branch.status_reason} +

+ )} +
+ {branch.step_count} step{branch.step_count !== 1 ? 's' : ''} +
+
+
+ ) } diff --git a/frontend/src/components/session/ForkCard.tsx b/frontend/src/components/session/ForkCard.tsx index 623fe385..4a00ff0c 100644 --- a/frontend/src/components/session/ForkCard.tsx +++ b/frontend/src/components/session/ForkCard.tsx @@ -14,7 +14,7 @@ export function ForkCard({ fork, selectedBranchId, onSelectOption }: ForkCardPro {/* Header */}
- + Fork Point
diff --git a/frontend/src/pages/DevBranchingPage.tsx b/frontend/src/pages/DevBranchingPage.tsx index d2da963e..ddff196a 100644 --- a/frontend/src/pages/DevBranchingPage.tsx +++ b/frontend/src/pages/DevBranchingPage.tsx @@ -5,7 +5,7 @@ * Renders all branching components with mock data — no API calls. * Use this to validate visual design before wiring into FlowPilotSessionPage. */ -import { useState } from 'react' +import { useState, useCallback, useEffect, useRef } from 'react' import { BranchMap } from '@/components/session/BranchMap' import { ForkCard } from '@/components/session/ForkCard' import { BranchTransitionBar } from '@/components/session/BranchTransitionBar' @@ -421,6 +421,8 @@ export default function DevBranchingPage() { const [showHandoff, setShowHandoff] = useState(false) const [previousBranchId, setPreviousBranchId] = useState(null) const [showTransition, setShowTransition] = useState(false) + const [sidebarWidth, setSidebarWidth] = useState(280) + const [isResizing, setIsResizing] = useState(false) const activeBranch = MOCK_BRANCHES.find(b => b.id === activeBranchId)! const previousBranch = previousBranchId ? MOCK_BRANCHES.find(b => b.id === previousBranchId) ?? null : null @@ -436,15 +438,61 @@ export default function DevBranchingPage() { } } + // ── Resizable sidebar ── + const sidebarRef = useRef(null) + const isResizingRef = useRef(false) + + const handleMouseDown = useCallback((e: React.MouseEvent) => { + e.preventDefault() + isResizingRef.current = true + setIsResizing(true) + document.body.style.cursor = 'col-resize' + document.body.style.userSelect = 'none' + }, []) + + useEffect(() => { + function handleMouseMove(e: MouseEvent) { + if (!isResizingRef.current) return + const newWidth = Math.min(Math.max(e.clientX, 200), 500) + setSidebarWidth(newWidth) + } + function handleMouseUp() { + if (!isResizingRef.current) return + isResizingRef.current = false + setIsResizing(false) + document.body.style.cursor = '' + document.body.style.userSelect = '' + } + document.addEventListener('mousemove', handleMouseMove) + document.addEventListener('mouseup', handleMouseUp) + return () => { + document.removeEventListener('mousemove', handleMouseMove) + document.removeEventListener('mouseup', handleMouseUp) + } + }, []) + return (
{/* Branch Map Sidebar */} -