/** * Stack Visualization Component * Visual tree/timeline showing stacked PRs with status and navigation */ import React from "react"; import { GitPullRequest, GitMerge, CircleDot, Circle, FileEdit, ChevronRight, Layers, ArrowUp } from "lucide-react"; interface StackEntry { order: number; pr: { id: string; number: number; title: string; state: string; isDraft: boolean; headBranch: string; isMerged: boolean; }; parentPrId: string | null; } interface StackVisualizationProps { stackId: string; stackName?: string; baseBranch: string; entries: StackEntry[]; currentPrId?: string; owner: string; repo: string; onReorder?: (newOrder: string[]) => void; compact?: boolean; } export function StackVisualization({ stackId, stackName, baseBranch, entries, currentPrId, owner, repo, onReorder, compact = false, }: StackVisualizationProps) { const getStatusIcon = (entry: StackEntry) => { if (entry.pr.isMerged) { return ; } if (entry.pr.isDraft) { return ; } if (entry.pr.state === "open") { return ; } return ; }; const getStatusColor = (entry: StackEntry) => { if (entry.pr.isMerged) return "border-purple-500 bg-purple-500/10"; if (entry.pr.isDraft) return "border-gray-400 bg-gray-400/10"; if (entry.pr.state === "open") return "border-green-500 bg-green-500/10"; return "border-red-500 bg-red-500/10"; }; const sortedEntries = [...entries].sort((a, b) => a.order - b.order); if (compact) { return (
Stack of {entries.length}
{sortedEntries.map((entry, i) => ( #{entry.pr.number} {i < sortedEntries.length - 1 && ( )} ))}
); } return (
{/* Header */}

{stackName || "Stacked Changes"}

{entries.length} PRs
Base: {baseBranch}
{/* Stack Visualization */}
{/* Vertical line */}
{/* Base branch indicator */}
{baseBranch}
Base branch
{/* Stack entries */} {sortedEntries.map((entry, index) => { const isCurrent = entry.pr.id === currentPrId; const isLast = index === sortedEntries.length - 1; return ( ); })}
{/* Actions */}
{sortedEntries.filter((e) => e.pr.isMerged).length} of {entries.length} merged
); } export default StackVisualization;