1- import type { ScopedThreadRef , ThreadPullRequestLink } from "@t3tools/contracts" ;
1+ import type { ProjectId , ScopedThreadRef , ThreadPullRequestLink } from "@t3tools/contracts" ;
2+ import { detectSourceControlProviderFromRemoteUrl } from "@t3tools/shared/sourceControl" ;
23import {
34 resolveThreadPullRequestChains ,
45 visibleThreadPullRequests ,
@@ -14,9 +15,10 @@ import {
1415import { useCallback , useMemo , useState } from "react" ;
1516
1617import { writeTextToClipboard } from "~/hooks/useCopyToClipboard" ;
17- import { useOpenPrLink } from "~/lib/openPullRequestLink" ;
18+ import { findProjectForChangeRequest , useOpenPrLink } from "~/lib/openPullRequestLink" ;
1819import { cn } from "~/lib/utils" ;
19- import { useServerConfigs , useThreadShell } from "~/state/entities" ;
20+ import { useShortcutModifierState } from "~/shortcutModifierState" ;
21+ import { useProjects , useServerConfigs , useThreadShell } from "~/state/entities" ;
2022import { PullRequestsUnavailableState } from "./PullRequestsUnavailableState" ;
2123import { threadEnvironment } from "~/state/threads" ;
2224import { useAtomCommand } from "~/state/use-atom-command" ;
@@ -42,6 +44,7 @@ import {
4244 pullRequestChecksStatePresentation ,
4345} from "./pullRequestPresentation" ;
4446import { PullRequestGlyph } from "./pullRequestIcons" ;
47+ import { PullRequestSpeedActions } from "./PullRequestSpeedActions" ;
4548
4649const SOURCE_LABELS : Record < ThreadPullRequestLink [ "source" ] , string > = {
4750 manual : "Linked by you" ,
@@ -74,11 +77,15 @@ function ChecksGlyph({
7477function LinkRow ( {
7578 line,
7679 threadRef,
80+ projectId,
81+ speedMode,
7782 onUnlink,
7883 onSetWatching,
7984} : {
8085 line : PullRequestListLine ;
8186 threadRef : ScopedThreadRef ;
87+ projectId : ProjectId | null ;
88+ speedMode : boolean ;
8289 onUnlink : ( link : ThreadPullRequestLink ) => void ;
8390 /** Null when the environment cannot watch pull requests. */
8491 onSetWatching : ( ( link : ThreadPullRequestLink , watching : boolean ) => void ) | null ;
@@ -97,6 +104,22 @@ function LinkRow({
97104 const snapshot = link . snapshot ;
98105 const open = snapshot === null || snapshot . state === "open" ;
99106 const watching = link . watch !== undefined ;
107+ const actionEntry =
108+ projectId !== null &&
109+ snapshot !== null &&
110+ snapshot . state !== "merged" &&
111+ detectSourceControlProviderFromRemoteUrl ( link . url ) ?. kind === "github"
112+ ? {
113+ environmentId : threadRef . environmentId ,
114+ projectId,
115+ host : link . host ,
116+ repository : link . repository ,
117+ number : link . number ,
118+ state : snapshot . state ,
119+ isDraft : snapshot . isDraft ,
120+ ...( link . stack === null ? { } : { stack : link . stack } ) ,
121+ }
122+ : null ;
100123 return (
101124 < div
102125 className = { cn ( PULL_REQUEST_ROW_CLASS , "relative hover:bg-accent/60" ) }
@@ -221,6 +244,9 @@ function LinkRow({
221244 updatedAt = { snapshot ?. updatedAt }
222245 />
223246 </ a >
247+ { actionEntry !== null ? (
248+ < PullRequestSpeedActions entry = { actionEntry } visible = { speedMode } />
249+ ) : null }
224250 { /* Out of the row's flow, so no row reserves a column for a button only the hovered one
225251 shows. It sits over the right end of the second line on the row's own hover color,
226252 fading in from the left, so it covers the time and leaves the diff counts alone. */ }
@@ -233,6 +259,8 @@ function LinkRow({
233259 "pointer-events-none opacity-0 group-hover/pr-row:pointer-events-auto group-hover/pr-row:opacity-100" ,
234260 "has-[[data-popup-open]]:pointer-events-auto has-[[data-popup-open]]:opacity-100" ,
235261 "has-[:focus-visible]:pointer-events-auto has-[:focus-visible]:opacity-100" ,
262+ "group-has-[[data-pull-request-action-pending=true]]/pr-row:hidden" ,
263+ speedMode && actionEntry !== null && "hidden" ,
236264 ) }
237265 >
238266 < span aria-hidden className = "absolute inset-0 bg-accent/60" />
@@ -301,12 +329,24 @@ export function ThreadPullRequestsPanel({ threadRef }: { threadRef: ScopedThread
301329
302330function EnabledThreadPullRequestsPanel ( { threadRef } : { threadRef : ScopedThreadRef } ) {
303331 const thread = useThreadShell ( threadRef ) ;
332+ const projects = useProjects ( ) ;
333+ const environmentProjects = useMemo (
334+ ( ) =>
335+ projects
336+ . filter ( ( project ) => project . environmentId === threadRef . environmentId )
337+ . toSorted ( ( left , right ) =>
338+ left . id === thread ?. projectId ? - 1 : right . id === thread ?. projectId ? 1 : 0 ,
339+ ) ,
340+ [ projects , threadRef . environmentId , thread ?. projectId ] ,
341+ ) ;
342+ const modifiers = useShortcutModifierState ( true ) ;
343+ const speedMode =
344+ modifiers . shiftKey && ! modifiers . metaKey && ! modifiers . ctrlKey && ! modifiers . altKey ;
304345 const openLinkDialog = useCallback ( ( ) => openLinkPullRequestDialog ( threadRef ) , [ threadRef ] ) ;
305346 const unlink = useAtomCommand ( threadEnvironment . unlinkPullRequest , { reportFailure : true } ) ;
306347 const watch = useAtomCommand ( threadEnvironment . watchPullRequest , { reportFailure : true } ) ;
307- const supportsWatch =
308- useServerConfigs ( ) . get ( threadRef . environmentId ) ?. environment . capabilities
309- . threadPullRequestWatch === true ;
348+ const capabilities = useServerConfigs ( ) . get ( threadRef . environmentId ) ?. environment . capabilities ;
349+ const supportsWatch = capabilities ?. threadPullRequestWatch === true ;
310350 const links = useMemo ( ( ) => visibleThreadPullRequests ( thread ?. pullRequests ?? [ ] ) , [ thread ] ) ;
311351 const lines = useMemo ( ( ) => pullRequestListLines ( resolveThreadPullRequestChains ( links ) ) , [ links ] ) ;
312352 const handleUnlink = useCallback (
@@ -377,6 +417,14 @@ function EnabledThreadPullRequestsPanel({ threadRef }: { threadRef: ScopedThread
377417 key = { `${ line . link . host } /${ line . link . repository } #${ line . link . number } ` }
378418 line = { line }
379419 threadRef = { threadRef }
420+ projectId = {
421+ capabilities ?. pullRequests === true
422+ ? ( findProjectForChangeRequest ( environmentProjects , line . link ) ?. id ??
423+ thread ?. projectId ??
424+ null )
425+ : null
426+ }
427+ speedMode = { speedMode }
380428 onUnlink = { handleUnlink }
381429 onSetWatching = { supportsWatch ? handleSetWatching : null }
382430 />
0 commit comments