"use client";
import { useState } from "react";
import { ChevronRight, ChevronDown, Circle, CheckCircle2, Clock } from "lucide-react";
import { cn } from "@/lib/utils";
export interface TreeNode {
id: string;
label: string;
status?: "built" | "in_progress" | "missing";
children?: TreeNode[];
metadata?: {
sessionsCount?: number;
commitsCount?: number;
cost?: number;
};
}
interface TreeViewProps {
data: TreeNode[];
selectedId?: string | null;
onSelect?: (node: TreeNode) => void;
className?: string;
}
interface TreeNodeItemProps {
node: TreeNode;
level: number;
selectedId?: string | null;
onSelect?: (node: TreeNode) => void;
}
function TreeNodeItem({ node, level, selectedId, onSelect }: TreeNodeItemProps) {
const [isExpanded, setIsExpanded] = useState(level === 0); // Auto-expand top level
const hasChildren = node.children && node.children.length > 0;
const isSelected = selectedId === node.id;
const getStatusIcon = () => {
if (!node.status) return null;
switch (node.status) {
case "built":
return ;
case "in_progress":
return ;
case "missing":
return ;
}
};
const getStatusColor = () => {
if (!node.status) return "";
switch (node.status) {
case "built":
return "bg-green-50 hover:bg-green-100 border-l-2 border-l-green-500";
case "in_progress":
return "bg-blue-50 hover:bg-blue-100 border-l-2 border-l-blue-500";
case "missing":
return "hover:bg-gray-100 border-l-2 border-l-transparent";
}
};
return (
0 && "text-sm"
)}
style={{ paddingLeft: `${level * 12 + 8}px` }}
onClick={() => {
if (hasChildren) {
setIsExpanded(!isExpanded);
}
if (onSelect) {
onSelect(node);
}
}}
>
{hasChildren ? (
) : (
{getStatusIcon()}
)}
1 && "text-muted-foreground"
)}>
{node.label}
{node.metadata && (
{node.metadata.sessionsCount && node.metadata.sessionsCount > 0 && (
{node.metadata.sessionsCount}s
)}
{node.metadata.commitsCount && node.metadata.commitsCount > 0 && (
{node.metadata.commitsCount}c
)}
)}
{hasChildren && isExpanded && (
{node.children!.map((child) => (
))}
)}
);
}
export function TreeView({ data, selectedId, onSelect, className }: TreeViewProps) {
return (
{data.map((node) => (
))}
);
}