11import { GitMergeIcon , GitPullRequestIcon } from "@phosphor-icons/react" ;
2+ import { parsePrUrl } from "@posthog/core/inbox/reportPresentation" ;
23import { cn } from "@posthog/quill" ;
34import { usePrDetails } from "@posthog/ui/features/git-interaction/usePrDetails" ;
5+ import { usePrDiffStatsFromBatch } from "@posthog/ui/features/inbox/context/PrDiffStatsBatchContext" ;
46import { Tooltip } from "@radix-ui/themes" ;
57
68export type ImplementationPrLinkSize = "sm" | "md" ;
@@ -13,41 +15,47 @@ interface ReportImplementationPrLinkProps {
1315 onLinkClick ?: ( ) => void ;
1416}
1517
16- function parseGitHubPrReference ( prUrl : string ) : {
17- reference : string ;
18- prNumber : string ;
19- } {
20- try {
21- const parsed = new URL ( prUrl ) ;
22- const match = parsed . pathname . match (
23- / ^ \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) \/ p u l l \/ ( \d + ) (?: $ | [ / ? # ] ) / ,
24- ) ;
25- if ( match ) {
26- return {
27- reference : `${ match [ 1 ] } /${ match [ 2 ] } #${ match [ 3 ] } ` ,
28- prNumber : `#${ match [ 3 ] } ` ,
29- } ;
30- }
31- } catch {
32- // Fall through to regex fallback for non-URL-safe inputs
33- }
34-
35- const prMatch = prUrl . match ( / \/ p u l l \/ ( \d + ) (?: $ | [ / ? # ] ) / ) ;
36- const prNumber = prMatch ? `#${ prMatch [ 1 ] } ` : "PR" ;
37- return {
38- reference : prUrl ,
39- prNumber,
40- } ;
41- }
18+ /** The only states we render a badge for; anything else is treated as unknown. */
19+ const KNOWN_PR_STATES = new Set ( [ "open" , "closed" , "merged" ] ) ;
4220
4321export function ReportImplementationPrLink ( {
4422 prUrl,
4523 size = "sm" ,
4624 onLinkClick,
4725} : ReportImplementationPrLinkProps ) {
48- const {
49- meta : { state, merged, draft, isLoading } ,
50- } = usePrDetails ( prUrl ) ;
26+ // On list surfaces the surrounding `PrDiffStatsBatchContext` already carries
27+ // this PR's status from the single batched request, so read it from there and
28+ // skip the per-PR query. Fall back to `usePrDetails` only on the standalone
29+ // detail view, where no batch provider is mounted.
30+ const batchEntry = usePrDiffStatsFromBatch ( prUrl ) ;
31+ const fallback = usePrDetails ( batchEntry . hasBatch ? null : prUrl ) ;
32+
33+ const state = batchEntry . hasBatch
34+ ? ( batchEntry . stats ?. state ?? null )
35+ : fallback . meta . state ;
36+ const merged = batchEntry . hasBatch
37+ ? ( batchEntry . stats ?. merged ?? false )
38+ : fallback . meta . merged ;
39+ const draft = batchEntry . hasBatch
40+ ? ( batchEntry . stats ?. draft ?? false )
41+ : fallback . meta . draft ;
42+ const isLoading = batchEntry . hasBatch
43+ ? batchEntry . isLoading && ! batchEntry . stats
44+ : fallback . meta . isLoading ;
45+
46+ // Only render for a canonical GitHub PR URL. This both keeps the badge in
47+ // sync with the gated "Open in GitHub" action and avoids turning an arbitrary
48+ // (possibly unsafe-scheme) string into a clickable external link.
49+ const prRef = parsePrUrl ( prUrl ) ;
50+ if ( ! prRef ) return null ;
51+
52+ // `getPrDetailsByUrl` falls back to `{ state: "unknown" }` when the lookup
53+ // fails (gh offline, private repo, unparseable URL), and a batch miss leaves
54+ // state null. Once settled, render nothing for an unresolved state rather
55+ // than a misleading green "open" badge.
56+ if ( ! isLoading && ( state === null || ! KNOWN_PR_STATES . has ( state ) ) ) {
57+ return null ;
58+ }
5159
5260 const isSm = size === "sm" ;
5361
@@ -63,15 +71,18 @@ export function ReportImplementationPrLink({
6371 ? "bg-gray-4 text-gray-11 hover:bg-gray-5"
6472 : "bg-green-4 text-green-11 hover:bg-green-5" ;
6573
66- const { reference : prReference , prNumber } = parseGitHubPrReference ( prUrl ) ;
74+ const prReference = `${ prRef . repoSlug } #${ prRef . number } ` ;
75+ const prNumber = `#${ prRef . number } ` ;
6776
68- const tooltip = merged
69- ? `Merged – ${ prReference } `
70- : state === "closed"
71- ? `Closed – ${ prReference } `
72- : draft
73- ? `Draft – ${ prReference } `
74- : `Open – ${ prReference } ` ;
77+ const tooltip = isLoading
78+ ? prReference
79+ : merged
80+ ? `Merged – ${ prReference } `
81+ : state === "closed"
82+ ? `Closed – ${ prReference } `
83+ : draft
84+ ? `Draft – ${ prReference } `
85+ : `Open – ${ prReference } ` ;
7586
7687 const iconSize = isSm ? 10 : 12 ;
7788
0 commit comments