@@ -26,7 +26,15 @@ import type {
2626 PullRequestReviewComment ,
2727} from '../github/pullRequestTimelineTypes' ;
2828import type { PullsQueryInput , PullsWithPageInfo } from '../github/pullsTypes' ;
29- import type { Blob , Commit , DateTime , GitObjectID , ID , Version , VersionCommit } from '../github/types' ;
29+ import type {
30+ Blob ,
31+ Commit ,
32+ DateTime ,
33+ GitObjectID ,
34+ ID ,
35+ Version ,
36+ VersionCommit ,
37+ } from '../github/types' ;
3038
3139import { UserHomePageQuery } from '../generated/graphql' ;
3240import CachingGitHubClient , { openDatabase } from '../github/CachingGitHubClient' ;
@@ -260,9 +268,7 @@ export const gitHubPullRequestViewerDidAuthorAtom = atom<boolean>(get => {
260268export const gitHubCurrentCommitAtom = atom < Promise < Commit | null > > ( async get => {
261269 const client = await get ( gitHubClientAtom ) ;
262270 const oid = get ( gitHubCommitIDAtom ) ;
263- return ( client != null && oid != null ) ?
264- client . getCommit ( oid ) : null ;
265-
271+ return client != null && oid != null ? client . getCommit ( oid ) : null ;
266272} ) ;
267273
268274/**
@@ -538,6 +544,107 @@ export const gitHubPullRequestSelectedVersionCommitsAtom = atom<VersionCommit[]>
538544 return versions [ selectedVersionIndex ] ?. commits ?? [ ] ;
539545} ) ;
540546
547+ /**
548+ * Migrated from: gitHubPullRequestIsViewingLatest selector in recoil.ts
549+ *
550+ * Determines if the user is viewing the latest version of the PR.
551+ * Used to show/hide the "Back to Latest" link.
552+ */
553+ export const gitHubPullRequestIsViewingLatestAtom = atom < boolean > ( get => {
554+ const versions = get ( gitHubPullRequestVersionsAtom ) ;
555+ if ( versions . length === 0 ) {
556+ return true ; // Default to true during loading
557+ }
558+
559+ const selectedVersionIndex = get ( gitHubPullRequestSelectedVersionIndexAtom ) ;
560+ if ( selectedVersionIndex !== versions . length - 1 ) {
561+ return false ; // Not on the latest version
562+ }
563+
564+ const comparableVersions = get ( gitHubPullRequestComparableVersionsAtom ) ;
565+ if ( comparableVersions == null ) {
566+ return true ; // No explicit comparison selected, assume latest
567+ }
568+
569+ // Viewing latest means: no explicit "before" selected, and "after" is the head commit
570+ const latestVersion = versions [ versions . length - 1 ] ;
571+ return (
572+ comparableVersions . beforeCommitID == null &&
573+ comparableVersions . afterCommitID === latestVersion . headCommit
574+ ) ;
575+ } ) ;
576+
577+ /**
578+ * Migrated from: gitHubPullRequestVersionIndexesByCommit selector in recoil.ts
579+ *
580+ * Internal atom that indexes versions by commit ID.
581+ */
582+ const gitHubPullRequestVersionIndexesByCommitAtom = atom < Map < GitObjectID , number > > ( get => {
583+ const versions = get ( gitHubPullRequestVersionsAtom ) ;
584+ const versionIndexByCommit = new Map < GitObjectID , number > ( ) ;
585+ versions . forEach ( ( { commits} , index ) => {
586+ commits . forEach ( commit => {
587+ versionIndexByCommit . set ( commit . commit , index ) ;
588+ } ) ;
589+ } ) ;
590+ return versionIndexByCommit ;
591+ } ) ;
592+
593+ /**
594+ * Migrated from: gitHubPullRequestVersionIndexForCommit selectorFamily in recoil.ts
595+ *
596+ * Looks up the version index for a given commit.
597+ * Used to navigate to the version containing a specific commit.
598+ */
599+ export const gitHubPullRequestVersionIndexForCommitAtom = atomFamily (
600+ ( commit : GitObjectID ) =>
601+ atom < number | null > ( get => {
602+ const versionIndexesByCommit = get ( gitHubPullRequestVersionIndexesByCommitAtom ) ;
603+ return versionIndexesByCommit . get ( commit ) ?? null ;
604+ } ) ,
605+ ( a , b ) => a === b ,
606+ ) ;
607+
608+ /**
609+ * Migrated from: gitHubPullRequestThreadsByCommit selector in recoil.ts
610+ *
611+ * Groups review threads by commit ID.
612+ * Used to count comments per version.
613+ */
614+ export const gitHubPullRequestThreadsByCommitAtom = atom <
615+ Map < GitObjectID , GitHubPullRequestReviewThread [ ] >
616+ > ( get => {
617+ const reviewThreads = get ( gitHubPullRequestReviewThreadsAtom ) ;
618+ const threadsByCommit = new Map < GitObjectID , GitHubPullRequestReviewThread [ ] > ( ) ;
619+
620+ reviewThreads . forEach ( thread => {
621+ // All comments in the thread should have the same original commit as the first
622+ const firstComment = thread . comments [ 0 ] ;
623+ const commitOid = firstComment ?. originalCommit ?. oid ;
624+ if ( commitOid != null ) {
625+ const existing = threadsByCommit . get ( commitOid ) ?? [ ] ;
626+ existing . push ( thread ) ;
627+ threadsByCommit . set ( commitOid , existing ) ;
628+ }
629+ } ) ;
630+
631+ return threadsByCommit ;
632+ } ) ;
633+
634+ /**
635+ * Migrated from: gitHubPullRequestThreadsForCommit selectorFamily in recoil.ts
636+ *
637+ * Gets review threads for a specific commit.
638+ */
639+ export const gitHubPullRequestThreadsForCommitAtom = atomFamily (
640+ ( commitID : GitObjectID ) =>
641+ atom < GitHubPullRequestReviewThread [ ] > ( get => {
642+ const reviewThreadsByCommit = get ( gitHubPullRequestThreadsByCommitAtom ) ;
643+ return reviewThreadsByCommit . get ( commitID ) ?? [ ] ;
644+ } ) ,
645+ ( a , b ) => a === b ,
646+ ) ;
647+
541648// =============================================================================
542649// Pull Request Review Threads
543650// =============================================================================
0 commit comments