1import { scopeProjectRef } from "@t3tools/client-runtime/environment";
2import { EnvironmentId, ProjectId, type ScopedThreadRef } from "@t3tools/contracts";
3
4import {
5 readPullRequestDetailSnapshot,
6 resolvePullRequestReferenceHost,
7} from "../components/pullRequest/pullRequestDetail.logic";
8import { projectChangeRequestUrl } from "@t3tools/client-runtime/change-request-links";
9import { selectActiveRightPanelSurface, useRightPanelStore } from "../rightPanelStore";
10import { useProject } from "../state/entities";
11import { pullRequestEnvironment } from "../state/pullRequests";
12import { useEnvironmentQuery } from "../state/query";
13import { useSupportsMultiplePullRequests } from "./useSupportsMultiplePullRequests";
14
15type PanelPullRequestSurface = Extract<
16 NonNullable<ReturnType<typeof selectActiveRightPanelSurface>>,
17 { kind: "pull-request" }
18>;
19
20function panelPullRequestReference(
21 requestedReference: PanelPullRequestSurface | null,
22 supportsMultiplePullRequests: boolean,
23 repositoryIdentity: Parameters<typeof resolvePullRequestReferenceHost>[1],
24) {
25 if (requestedReference === null) return null;
26 const input = {
27 projectId: ProjectId.make(requestedReference.projectId),
28 repository: requestedReference.repository,
29 number: requestedReference.number,
30 };
31 return supportsMultiplePullRequests
32 ? resolvePullRequestReferenceHost(
33 {
34 ...input,
35 ...(requestedReference.host === undefined ? {} : { host: requestedReference.host }),
36 },
37 repositoryIdentity,
38 )
39 : input;
40}
41
42export function useOpenPanelPullRequestUrl(threadRef: ScopedThreadRef | null) {
43 const surface = useRightPanelStore((state) =>
44 selectActiveRightPanelSurface(state.byThreadKey, threadRef),
45 );
46 const requestedReference = surface?.kind === "pull-request" ? surface : null;
47 const environmentId = requestedReference?.environmentId
48 ? EnvironmentId.make(requestedReference.environmentId)
49 : threadRef?.environmentId;
50 const supportsMultiplePullRequests = useSupportsMultiplePullRequests(environmentId ?? null);
51 const project = useProject(
52 requestedReference && environmentId
53 ? scopeProjectRef(environmentId, ProjectId.make(requestedReference.projectId))
54 : null,
55 );
56 const reference = panelPullRequestReference(
57 requestedReference,
58 supportsMultiplePullRequests,
59 project?.repositoryIdentity,
60 );
61 // Keep all reference/project reads before the query hook to preserve caching of reference and its detail atom.
62 const cachedDetail =
63 reference && environmentId
64 ? readPullRequestDetailSnapshot(
65 typeof window === "undefined" ? undefined : window.localStorage,
66 environmentId,
67 reference,
68 )
69 : null;
70 const fallbackUrl = reference
71 ? (requestedReference?.url ??
72 projectChangeRequestUrl(project?.repositoryIdentity, reference.repository, reference.number))
73 : undefined;
74 const detail = useEnvironmentQuery(
75 reference && environmentId
76 ? pullRequestEnvironment.detail({
77 environmentId,
78 input: { ...reference, allowStale: false },
79 })
80 : null,
81 ).data;
82 return reference ? ((detail ?? cachedDetail)?.url ?? fallbackUrl) : undefined;
83}