({
pr,
onBack,
onIndex,
onSelectInGraph,
llm,
store,
prClient,
onChatWithPR,
}: Props)
| 80 | } |
| 81 | |
| 82 | export default function PRDetailPanel({ |
| 83 | pr, |
| 84 | onBack, |
| 85 | onIndex, |
| 86 | onSelectInGraph, |
| 87 | llm, |
| 88 | store, |
| 89 | prClient, |
| 90 | onChatWithPR, |
| 91 | }: Props) { |
| 92 | const [indexing, setIndexing] = useState(false); |
| 93 | const [indexed, setIndexed] = useState(false); |
| 94 | |
| 95 | // Review state |
| 96 | const [reviewing, setReviewing] = useState(false); |
| 97 | const [reviewSteps, setReviewSteps] = useState<string[]>([]); |
| 98 | const [reviewResult, setReviewResult] = useState<string | null>(null); |
| 99 | const [reviewError, setReviewError] = useState<string | null>(null); |
| 100 | const abortRef = useRef<AbortController | null>(null); |
| 101 | |
| 102 | const canReview = !!(llm && store); |
| 103 | |
| 104 | // Check if this PR is already indexed in the graph |
| 105 | useEffect(() => { |
| 106 | if (!store || !prClient) return; |
| 107 | const prId = `${prClient.meta.owner}/${prClient.meta.repo}/pr/${pr.number}`; |
| 108 | store |
| 109 | .getNode(prId) |
| 110 | .then((node) => { |
| 111 | if (node) setIndexed(true); |
| 112 | }) |
| 113 | .catch(() => { |
| 114 | /* ignore */ |
| 115 | }); |
| 116 | }, [store, prClient, pr.number]); |
| 117 | |
| 118 | const handleIndex = async () => { |
| 119 | setIndexing(true); |
| 120 | try { |
| 121 | await onIndex(pr); |
| 122 | setIndexed(true); |
| 123 | } finally { |
| 124 | setIndexing(false); |
| 125 | } |
| 126 | }; |
| 127 | |
| 128 | const handleRunReview = async () => { |
| 129 | if (!llm || !store) return; |
| 130 | |
| 131 | // Auto-index if not yet indexed — the review agent needs PR data in the graph |
| 132 | if (!indexed) { |
| 133 | setIndexing(true); |
| 134 | try { |
| 135 | await onIndex(pr); |
| 136 | setIndexed(true); |
| 137 | } catch (err) { |
| 138 | setReviewError( |
| 139 | `Failed to index PR: ${err instanceof Error ? err.message : String(err)}`, |
nothing calls this directly
no test coverage detected