@@ -457,6 +457,7 @@ function createGitHubStore() {
457457 let octokit : Octokit | null = null ;
458458 let batcher : GraphQLBatcher | null = null ;
459459 let onUnauthorized : ( ( ) => void ) | null = null ;
460+ let prListAbortController : AbortController | null = null ;
460461 let onRateLimited : ( ( ) => void ) | null = null ;
461462
462463 function setOnUnauthorized ( callback : ( ) => void ) {
@@ -641,9 +642,21 @@ function createGitHubStore() {
641642 // PR List
642643 // ---------------------------------------------------------------------------
643644
644- async function fetchPRList ( queries : string [ ] , page = 1 , perPage = 30 ) {
645+ async function fetchPRList (
646+ queries : string [ ] ,
647+ page = 1 ,
648+ perPage = 30 ,
649+ options ?: { backgroundRefresh ?: boolean }
650+ ) {
645651 if ( ! octokit || ! batcher ) return ;
646652
653+ const { backgroundRefresh = false } = options ?? { } ;
654+
655+ // Abort any in-flight request
656+ prListAbortController ?. abort ( ) ;
657+ const abortController = new AbortController ( ) ;
658+ prListAbortController = abortController ;
659+
647660 if ( queries . length === 0 ) {
648661 setState ( {
649662 prList : {
@@ -671,7 +684,8 @@ function createGitHubStore() {
671684 setState ( {
672685 prList : {
673686 ...stale . data ,
674- loading : stale . isStale ,
687+ // Don't show loading state for background refreshes
688+ loading : backgroundRefresh ? false : stale . isStale ,
675689 error : null ,
676690 lastFetchedAt : Date . now ( ) ,
677691 } ,
@@ -680,7 +694,8 @@ function createGitHubStore() {
680694 } ) ;
681695 // If fresh, don't revalidate
682696 if ( ! stale . isStale ) return ;
683- } else {
697+ } else if ( ! backgroundRefresh ) {
698+ // Only show loading state if this is not a background refresh
684699 setState ( ( s ) => ( {
685700 prList : { ...s . prList , loading : true , error : null } ,
686701 prListQueries : queries ,
@@ -689,11 +704,14 @@ function createGitHubStore() {
689704 }
690705
691706 try {
692- // Fetch PRs with caching
707+ // Fetch PRs with caching, passing the abort signal
693708 const results = await Promise . all (
694- queries . map ( ( q ) => searchPRs ( q , page , perPage ) )
709+ queries . map ( ( q ) => searchPRs ( q , page , perPage , abortController . signal ) )
695710 ) ;
696711
712+ // Check if aborted before processing results
713+ if ( abortController . signal . aborted ) return ;
714+
697715 // Combine and dedupe by PR id
698716 const seen = new Set < number > ( ) ;
699717 const combined : PRSearchResult [ ] = [ ] ;
@@ -732,6 +750,10 @@ function createGitHubStore() {
732750 if ( prIdentifiers . length > 0 ) {
733751 try {
734752 const enrichmentMap = await getPREnrichment ( prIdentifiers ) ;
753+
754+ // Check if aborted after enrichment
755+ if ( abortController . signal . aborted ) return ;
756+
735757 for ( const item of combined ) {
736758 const match = item . repository_url ?. match ( / r e p o s \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) / ) ;
737759 if ( match && item . number ) {
@@ -747,6 +769,9 @@ function createGitHubStore() {
747769 }
748770 }
749771
772+ // Final check before updating state
773+ if ( abortController . signal . aborted ) return ;
774+
750775 // Cache the result (persist for instant load next time)
751776 // Use combined.length instead of total to reflect deduplicated count
752777 cache . set (
@@ -765,6 +790,12 @@ function createGitHubStore() {
765790 } ,
766791 } ) ;
767792 } catch ( e ) {
793+ // Ignore abort errors - they're expected when switching filters
794+ if ( e instanceof Error && e . name === "AbortError" ) return ;
795+
796+ // Only update error state if not aborted
797+ if ( abortController . signal . aborted ) return ;
798+
768799 setState ( ( s ) => ( {
769800 prList : {
770801 ...s . prList ,
@@ -778,7 +809,7 @@ function createGitHubStore() {
778809 function refreshPRList ( ) {
779810 const { prListQueries, prListPage } = state ;
780811 if ( prListQueries . length > 0 ) {
781- fetchPRList ( prListQueries , prListPage ) ;
812+ fetchPRList ( prListQueries , prListPage , 30 , { backgroundRefresh : true } ) ;
782813 }
783814 }
784815
@@ -919,7 +950,12 @@ function createGitHubStore() {
919950 // API Methods (with caching and deduplication)
920951 // ---------------------------------------------------------------------------
921952
922- async function searchPRs ( query : string , page = 1 , perPage = 30 ) {
953+ async function searchPRs (
954+ query : string ,
955+ page = 1 ,
956+ perPage = 30 ,
957+ signal ?: AbortSignal
958+ ) {
923959 if ( ! octokit ) throw new Error ( "Not initialized" ) ;
924960
925961 const cacheKey = `search:prs:${ query } :${ page } :${ perPage } ` ;
@@ -947,6 +983,7 @@ function createGitHubStore() {
947983 order : "desc" ,
948984 per_page : perPage ,
949985 page,
986+ request : { signal } ,
950987 } )
951988 . then ( ( res ) => {
952989 cache . set ( cacheKey , res . data ) ;
0 commit comments