1import { useAtomValue } from "@effect/atom-react";
2import { ThreadPullRequestLink, type EnvironmentId, type PullRequestRef } from "@t3tools/contracts";
3import { Atom } from "effect/reactivity";
4import * as Schema from "effect/Schema";
5import {
6 savedPullRequestStack,
7 pullRequestStackView,
8} from "../components/pullRequest/pullRequestStackSnapshot";
9import { pullRequestStackAtom } from "./pullRequests";
10import { useEnvironmentQuery } from "./query";
11import { environmentThreadShells } from "./threads";
12
13const sameLinks = Schema.toEquivalence(Schema.Array(ThreadPullRequestLink));
14
15// Shell pushes recreate link arrays; reuse equal lists so streaming does not re-render the stack.
16const environmentPullRequestLinksAtom = Atom.family((environmentId: EnvironmentId) => {
17 let previous: ReadonlyArray<ThreadPullRequestLink> = [];
18 return Atom.make((get) => {
19 const next = get(environmentThreadShells.environmentThreadsAtom(environmentId)).flatMap(
20 (thread) => thread.pullRequests ?? [],
21 );
22 if (sameLinks(previous, next)) return previous;
23 previous = next;
24 return next;
25 }).pipe(Atom.withLabel(`web-environment-pull-request-links:${environmentId}`));
26});
27
28export function usePullRequestStack(
29 environmentId: EnvironmentId,
30 reference: PullRequestRef | null,
31) {
32 const links = useAtomValue(environmentPullRequestLinksAtom(environmentId));
33 const saved = reference === null ? null : savedPullRequestStack(links, reference);
34 const query = useEnvironmentQuery(
35 reference === null ? null : pullRequestStackAtom({ environmentId, input: reference }),
36 );
37 return { ...query, ...pullRequestStackView(query, saved) };
38}