@@ -78,6 +78,7 @@ import { RightPanelTabs } from "../RightPanelTabs";
7878import { isCommandPaletteOpen } from "~/commandPaletteBus" ;
7979import { isElectron } from "~/env" ;
8080import { resolveShortcutCommand , shortcutLabelForCommand } from "~/keybindings" ;
81+ import { registerCommands } from "~/shortcuts/dispatcher" ;
8182import { isTerminalFocused } from "~/lib/terminalFocus" ;
8283import { PanelLayoutControls , RightPanelMaximizeControl } from "../chat/PanelLayoutControls" ;
8384import { Button } from "../ui/button" ;
@@ -286,13 +287,21 @@ export function PullRequestsPage() {
286287 * host forever.
287288 */
288289 regrown : ReadonlyArray < string > ;
289- } > ( { key : filterKey , size : PAGE_SIZE , cursors : null , regrown : [ ] } ) ;
290+ /** The turn refreshes a continuation was read under; a later turn makes its cursors stale. */
291+ turn : string ;
292+ } > ( { key : filterKey , size : PAGE_SIZE , cursors : null , regrown : [ ] , turn : turnRefreshToken } ) ;
290293 const pageSize = page . key === filterKey ? page . size : PAGE_SIZE ;
291294 const sentCursors = page . key === filterKey ? page . cursors : null ;
292295 const sentRegrown = page . key === filterKey ? page . regrown : [ ] ;
293296
294297 if ( page . key !== filterKey ) {
295- setPage ( { key : filterKey , size : PAGE_SIZE , cursors : null , regrown : [ ] } ) ;
298+ setPage ( {
299+ key : filterKey ,
300+ size : PAGE_SIZE ,
301+ cursors : null ,
302+ regrown : [ ] ,
303+ turn : turnRefreshToken ,
304+ } ) ;
296305 }
297306
298307 const listTargets = environmentQueries . flatMap ( ( { environmentId, projectIds } ) => {
@@ -591,6 +600,7 @@ export function PullRequestsPage() {
591600 size : regrown . length === 0 ? pageSize : Math . min ( pageSize + PAGE_SIZE , MAX_PAGE_SIZE ) ,
592601 cursors : nextCursors ,
593602 regrown,
603+ turn : turnRefreshToken ,
594604 } ) ;
595605 return ;
596606 }
@@ -599,9 +609,28 @@ export function PullRequestsPage() {
599609 size : Math . min ( pageSize + PAGE_SIZE , MAX_PAGE_SIZE ) ,
600610 cursors : null ,
601611 regrown : [ ] ,
612+ turn : turnRefreshToken ,
602613 } ) ;
603614 } ;
604615
616+ const collapsedPage = ( ) => {
617+ const loadedCount =
618+ ordered ?. key === filterKey ? largestPullRequestReadCount ( ordered . entries ) : pageSize ;
619+ return {
620+ key : filterKey ,
621+ regrown : [ ] ,
622+ size : Math . min (
623+ Math . max ( pageSize , Math . ceil ( loadedCount / PAGE_SIZE ) * PAGE_SIZE ) ,
624+ MAX_PAGE_SIZE ,
625+ ) ,
626+ cursors : null ,
627+ turn : turnRefreshToken ,
628+ } ;
629+ } ;
630+ // Every list read refetches itself when a turn completes, but a continuation would refetch only
631+ // its later page and strand the rows before it, so the whole loaded list is asked for again.
632+ if ( sentCursors !== null && page . turn !== turnRefreshToken ) setPage ( collapsedPage ( ) ) ;
633+
605634 const refreshList = ( includeRelated = false , actedEnvironmentId ?: EnvironmentId ) => {
606635 const related = (
607636 includeRelated
@@ -627,31 +656,9 @@ export function PullRequestsPage() {
627656 return ;
628657 }
629658 if ( related . length > 0 ) listQuery . refresh ( related ) ;
630- const loadedCount =
631- ordered ?. key === filterKey ? largestPullRequestReadCount ( ordered . entries ) : pageSize ;
632- setPage ( {
633- key : filterKey ,
634- regrown : [ ] ,
635- size : Math . min (
636- Math . max ( pageSize , Math . ceil ( loadedCount / PAGE_SIZE ) * PAGE_SIZE ) ,
637- MAX_PAGE_SIZE ,
638- ) ,
639- cursors : null ,
640- } ) ;
659+ setPage ( collapsedPage ( ) ) ;
641660 } ;
642661
643- const appliedTurnRefreshToken = useRef ( "" ) ;
644- const refreshAfterTurn = useEffectEvent ( ( ) => {
645- if ( sentCursors !== null ) refreshList ( ) ;
646- } ) ;
647- useEffect ( ( ) => {
648- if ( turnRefreshToken . length === 0 || appliedTurnRefreshToken . current === turnRefreshToken ) {
649- return ;
650- }
651- appliedTurnRefreshToken . current = turnRefreshToken ;
652- refreshAfterTurn ( ) ;
653- } , [ turnRefreshToken ] ) ;
654-
655662 useLiveRefresh (
656663 ( ) => {
657664 refreshList ( true ) ;
@@ -917,15 +924,6 @@ export function PullRequestsPage() {
917924 // oxlint-disable-next-line react/exhaustive-effect-dependencies -- The pointer sensor lives outside React; a new list under a sweep in progress must end it.
918925 [ filterKey , search . q , sort ] ,
919926 ) ;
920- useEffect ( ( ) => {
921- const onKeyDown = ( event : KeyboardEvent ) => {
922- if ( event . key !== "Escape" || closeSensorRef . current === null ) return ;
923- event . preventDefault ( ) ;
924- closeSensorRef . current . cancel ( ) ;
925- } ;
926- document . addEventListener ( "keydown" , onKeyDown , true ) ;
927- return ( ) => document . removeEventListener ( "keydown" , onKeyDown , true ) ;
928- } , [ ] ) ;
929927 const startCloseSweep = useStableCallback (
930928 ( entry : EnvironmentPullRequestEntry , event : PointerEvent ) => {
931929 closeSensorRef . current ?. cancel ( ) ;
@@ -957,14 +955,27 @@ export function PullRequestsPage() {
957955 sweptKeys = resolveSidebarSweepKeys ( orderedKeys , originKey , key , canClose ) ;
958956 setCloseSweepKeys ( new Set ( sweptKeys ) ) ;
959957 } ;
960- closeSensorRef . current = new SidebarPointerSensor ( {
958+ // Only while a sweep runs: Escape ends it, ahead of any other scope that would also take it.
959+ const releaseEscape = registerCommands (
960+ { } ,
961+ {
962+ capture : true ,
963+ onKeyDown : ( keyEvent ) => {
964+ if ( keyEvent . key !== "Escape" ) return false ;
965+ keyEvent . preventDefault ( ) ;
966+ sensor . cancel ( ) ;
967+ } ,
968+ } ,
969+ ) ;
970+ const sensor = new SidebarPointerSensor ( {
961971 active : originKey ,
962972 event,
963973 options : {
964974 distance : 6 ,
965975 onAttach : ( ) => { } ,
966976 onFinish : ( ) => {
967- closeSensorRef . current = null ;
977+ releaseEscape ( ) ;
978+ if ( closeSensorRef . current === sensor ) closeSensorRef . current = null ;
968979 setCloseSweepKeys ( new Set ( ) ) ;
969980 } ,
970981 } ,
@@ -992,6 +1003,7 @@ export function PullRequestsPage() {
9921003 onCancel : ( ) => { } ,
9931004 onAbort : ( ) => { } ,
9941005 } ) ;
1006+ closeSensorRef . current = sensor ;
9951007 } ,
9961008 ) ;
9971009 const rightPanelAvailable = selectedPullRequestSurface !== null ;
0 commit comments