@@ -790,9 +790,16 @@ export const PROverview = memo(function PROverview() {
790790 } ) ;
791791 } ) ;
792792
793- // Add reviews with bodies
794- latestReviews
795- . filter ( ( r ) => r . body && r . submitted_at )
793+ // Add ALL reviews to timeline - show APPROVED/CHANGES_REQUESTED always, COMMENTED only if they have a body
794+ // Note: we use `reviews` not `latestReviews` because latestReviews only keeps one review per user
795+ reviews
796+ . filter (
797+ ( r ) =>
798+ r . submitted_at &&
799+ ( r . body ||
800+ r . state === "APPROVED" ||
801+ r . state === "CHANGES_REQUESTED" )
802+ )
796803 . forEach ( ( review ) => {
797804 entries . push ( {
798805 type : "review" ,
@@ -936,6 +943,8 @@ export const PROverview = memo(function PROverview() {
936943 setShowMergeOptions ( ! showMergeOptions )
937944 }
938945 onUpdateBranch = { handleUpdateBranch }
946+ markingReady = { markingReady }
947+ onMarkReadyForReview = { handleMarkReadyForReview }
939948 />
940949 { /* Still in progress - only show if NOT a draft and user can merge */ }
941950 { canMergeRepo && ! pr . draft && (
@@ -1446,24 +1455,6 @@ export const PROverview = memo(function PROverview() {
14461455 canWrite = { canMergeRepo }
14471456 />
14481457
1449- { /* Draft - Mark as ready for review */ }
1450- { canMergeRepo && pr . state === "open" && ! pr . merged && pr . draft && (
1451- < div className = "pt-2 border-t border-border" >
1452- < p className = "text-xs text-muted-foreground mb-1" >
1453- This pull request is still a work in progress.
1454- </ p >
1455- < button
1456- onClick = { handleMarkReadyForReview }
1457- disabled = { markingReady }
1458- className = "text-sm text-blue-400 hover:underline disabled:opacity-50"
1459- >
1460- { markingReady
1461- ? "Marking ready..."
1462- : "Mark as ready for review" }
1463- </ button >
1464- </ div >
1465- ) }
1466-
14671458 { /* Participants */ }
14681459 < SidebarSection
14691460 title = { `${ participants . length } participant${ participants . length !== 1 ? "s" : "" } ` }
@@ -2121,6 +2112,8 @@ function MergeSection({
21212112 onSetMergeMethod,
21222113 onToggleMergeOptions,
21232114 onUpdateBranch,
2115+ markingReady,
2116+ onMarkReadyForReview,
21242117} : {
21252118 pr : {
21262119 draft ?: boolean ;
@@ -2141,6 +2134,8 @@ function MergeSection({
21412134 onSetMergeMethod : ( method : "merge" | "squash" | "rebase" ) => void ;
21422135 onToggleMergeOptions : ( ) => void ;
21432136 onUpdateBranch : ( ) => void ;
2137+ markingReady ?: boolean ;
2138+ onMarkReadyForReview ?: ( ) => void ;
21442139} ) {
21452140 const buttonRef = useRef < HTMLButtonElement > ( null ) ;
21462141 const [ dropdownPosition , setDropdownPosition ] = useState ( {
@@ -2518,8 +2513,40 @@ function MergeSection({
25182513 </ div >
25192514 </ div >
25202515
2521- { /* Merge controls - only show when user can merge */ }
2522- { canMergeRepo && (
2516+ { /* Draft section - show when PR is a draft */ }
2517+ { pr . draft && (
2518+ < div className = "p-4" >
2519+ < div className = "flex items-start gap-3" >
2520+ < div className = "p-2 rounded-full bg-muted text-muted-foreground" >
2521+ < GitPullRequest className = "w-5 h-5" />
2522+ </ div >
2523+ < div className = "flex-1" >
2524+ < p className = "font-medium text-sm" >
2525+ This pull request is still a work in progress
2526+ </ p >
2527+ < p className = "text-xs text-muted-foreground" >
2528+ Draft pull requests cannot be merged.
2529+ </ p >
2530+ </ div >
2531+ { canMergeRepo && onMarkReadyForReview && (
2532+ < button
2533+ onClick = { onMarkReadyForReview }
2534+ disabled = { markingReady }
2535+ className = "px-3 py-1.5 border border-border rounded-md hover:bg-muted transition-colors text-sm font-medium disabled:opacity-50"
2536+ >
2537+ { markingReady ? (
2538+ < Loader2 className = "w-4 h-4 animate-spin" />
2539+ ) : (
2540+ "Ready for review"
2541+ ) }
2542+ </ button >
2543+ ) }
2544+ </ div >
2545+ </ div >
2546+ ) }
2547+
2548+ { /* Merge controls - only show when user can merge and PR is not a draft */ }
2549+ { canMergeRepo && ! pr . draft && (
25232550 < div className = "p-4 space-y-3" >
25242551 { mergeError && (
25252552 < p className = "text-sm text-destructive" > { mergeError } </ p >
@@ -3496,6 +3523,34 @@ function TimelineItem({ event, pr }: TimelineItemProps) {
34963523 } ;
34973524 }
34983525
3526+ case "head_ref_force_pushed" : {
3527+ // Timeline API only provides commit_id (the "to" SHA), no "before" SHA
3528+ const forcePush = event as { commit_id ?: string } ;
3529+ return {
3530+ icon : < GitBranch className = "w-4 h-4" /> ,
3531+ text : (
3532+ < span >
3533+ < span className = "font-medium" > { actor ?. login } </ span > force-pushed
3534+ the{ " " }
3535+ < code className = "px-1.5 py-0.5 bg-blue-500/20 text-blue-300 rounded text-xs" >
3536+ { pr ?. head ?. ref || "branch" }
3537+ </ code > { " " }
3538+ branch
3539+ { forcePush . commit_id && (
3540+ < >
3541+ { " " }
3542+ to{ " " }
3543+ < code className = "px-1.5 py-0.5 bg-muted rounded text-xs font-mono" >
3544+ { forcePush . commit_id . slice ( 0 , 7 ) }
3545+ </ code >
3546+ </ >
3547+ ) }
3548+ </ span >
3549+ ) ,
3550+ color : "text-amber-400" ,
3551+ } ;
3552+ }
3553+
34993554 case "merged" : {
35003555 const merged = event as { commit_id ?: string } ;
35013556 return {
0 commit comments