History

feat(prs): navigate, merge and rebase GitHub stacks (#10875)

Julius Marminge committed 2 months ago

Commit de379641 parent f0401c653 files · +3104 −464Browse files

Showing the changes to apps/web/src/components/pullRequest/pullRequestStackSnapshot.ts (1 of 53 files). Show all

Unified · Split

apps/web/src/components/pullRequest/pullRequestStackSnapshot.ts+73−0
@@ -0,0 +1,73 @@
1+import type { PullRequestRef, PullRequestStack, ThreadPullRequestLink } from "@t3tools/contracts";
2+
3+/** Saved native membership is enough for navigation, but never supplies action head SHAs. */
4+export function savedPullRequestStack(
5+ links: ReadonlyArray<ThreadPullRequestLink>,
6+ reference: PullRequestRef,
7+): PullRequestStack | null {
8+ const host = reference.host?.toLowerCase();
9+ if (!host) return null;
10+ const matching = links.filter(
11+ (link) =>
12+ link.host.toLowerCase() === host &&
13+ link.repository.toLowerCase() === reference.repository.toLowerCase(),
14+ );
15+ const exact = matching.filter((link) => link.number === reference.number);
16+ const candidates =
17+ exact.length > 0
18+ ? exact
19+ : matching.filter((link) =>
20+ link.stack?.layers.some((layer) => layer.number === reference.number),
21+ );
22+ const newest = candidates.toSorted(
23+ (a, b) =>
24+ Date.parse(b.snapshot?.syncedAt ?? b.linkedAt) -
25+ Date.parse(a.snapshot?.syncedAt ?? a.linkedAt),
26+ )[0];
27+ const stack = newest?.stack;
28+ if (!stack || !stack.layers.some((layer) => layer.number === reference.number)) return null;
29+ return {
30+ id: stack.id,
31+ number: stack.number,
32+ url: stack.url,
33+ base: stack.base,
34+ layers: stack.layers.map((layer) => {
35+ const snapshot = matching
36+ .filter((link) => link.number === layer.number)
37+ .toSorted(
38+ (a, b) =>
39+ Date.parse(b.snapshot?.syncedAt ?? b.linkedAt) -
40+ Date.parse(a.snapshot?.syncedAt ?? a.linkedAt),
41+ )[0]?.snapshot;
42+ return {
43+ ...layer,
44+ ...(snapshot ? { title: snapshot.title, isDraft: snapshot.isDraft } : {}),
45+ };
46+ }),
47+ };
48+}
49+
50+/** A fresh absence overrides saved membership; failed refreshes preserve available navigation. */
51+export function pullRequestStackView(
52+ query: {
53+ data: PullRequestStack | null;
54+ isSuccess: boolean;
55+ isPending: boolean;
56+ error: string | null;
57+ },
58+ saved: PullRequestStack | null,
59+) {
60+ const data = query.isSuccess ? query.data : (query.data ?? saved);
61+ return {
62+ data,
63+ isFresh: query.isSuccess && !query.isPending,
64+ notice:
65+ data === null
66+ ? null
67+ : query.error
68+ ? "Stack data may be stale. We couldn’t refresh it."
69+ : !query.isSuccess || query.isPending
70+ ? "Refreshing stack… Showing saved data."
71+ : null,
72+ };
73+}