| ... | @@ -20,6 +20,7 @@ import { | ... | @@ -20,6 +20,7 @@ import { |
| 20 | } from "react"; | 20 | } from "react"; |
| 21 | | 21 | |
| 22 | import { useComposerDraftStore, type DraftId } from "../composerDraftStore"; | 22 | import { useComposerDraftStore, type DraftId } from "../composerDraftStore"; |
| | 23 | import { useOpenPrLink } from "../lib/openPullRequestLink"; |
| 23 | import { usePaginatedBranches } from "../state/queries"; | 24 | import { usePaginatedBranches } from "../state/queries"; |
| 24 | import { useProject, useThread } from "../state/entities"; | 25 | import { useProject, useThread } from "../state/entities"; |
| 25 | import { useEnvironmentQuery } from "../state/query"; | 26 | import { useEnvironmentQuery } from "../state/query"; |
| ... | @@ -37,9 +38,13 @@ import { | ... | @@ -37,9 +38,13 @@ import { |
| 37 | resolveEffectiveEnvMode, | 38 | resolveEffectiveEnvMode, |
| 38 | shouldIncludeBranchPickerItem, | 39 | shouldIncludeBranchPickerItem, |
| 39 | } from "./BranchToolbar.logic"; | 40 | } from "./BranchToolbar.logic"; |
| | 41 | import { |
| | 42 | ChangeRequestStatusIcon, |
| | 43 | prStatusIndicator, |
| | 44 | resolveThreadPr, |
| | 45 | } from "./ThreadStatusIndicators"; |
| 40 | import { Button } from "./ui/button"; | 46 | import { Button } from "./ui/button"; |
| 41 | import { Switch } from "./ui/switch"; | 47 | import { Switch } from "./ui/switch"; |
| 42 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; | | |
| 43 | import { | 48 | import { |
| 44 | Combobox, | 49 | Combobox, |
| 45 | ComboboxEmpty, | 50 | ComboboxEmpty, |
| ... | @@ -51,6 +56,7 @@ import { | ... | @@ -51,6 +56,7 @@ import { |
| 51 | ComboboxTrigger, | 56 | ComboboxTrigger, |
| 52 | } from "./ui/combobox"; | 57 | } from "./ui/combobox"; |
| 53 | import { stackedThreadToast, toastManager } from "./ui/toast"; | 58 | import { stackedThreadToast, toastManager } from "./ui/toast"; |
| | 59 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; |
| 54 | | 60 | |
| 55 | interface BranchToolbarBranchSelectorProps { | 61 | interface BranchToolbarBranchSelectorProps { |
| 56 | className?: string; | 62 | className?: string; |
| ... | @@ -525,6 +531,16 @@ export function BranchToolbarBranchSelector({ | ... | @@ -525,6 +531,16 @@ export function BranchToolbarBranchSelector({ |
| 525 | resolvedActiveBranch, | 531 | resolvedActiveBranch, |
| 526 | }); | 532 | }); |
| 527 | | 533 | |
| | 534 | // PR pill shown next to the branch selector when the active branch has one. |
| | 535 | const branchPr = resolveThreadPr(resolvedActiveBranch, branchStatusQuery.data ?? null); |
| | 536 | const branchPrStatus = prStatusIndicator(branchPr, branchStatusQuery.data?.sourceControlProvider); |
| | 537 | // Action-oriented tooltip (the pill opens the PR), distinct from the sidebar's |
| | 538 | // state-description tooltip. |
| | 539 | const branchPrTooltip = branchPr |
| | 540 | ? `Open ${sourceControlPresentation.terminology.singular} #${branchPr.number} (${branchPr.state}) in browser` |
| | 541 | : ""; |
| | 542 | const openPrLink = useOpenPrLink(); |
| | 543 | |
| 528 | function renderPickerItem(itemValue: string, index: number) { | 544 | function renderPickerItem(itemValue: string, index: number) { |
| 529 | if (checkoutPullRequestItemValue && itemValue === checkoutPullRequestItemValue) { | 545 | if (checkoutPullRequestItemValue && itemValue === checkoutPullRequestItemValue) { |
| 530 | return ( | 546 | return ( |
| ... | @@ -621,15 +637,38 @@ export function BranchToolbarBranchSelector({ | ... | @@ -621,15 +637,38 @@ export function BranchToolbarBranchSelector({ |
| 621 | open={isBranchMenuOpen} | 637 | open={isBranchMenuOpen} |
| 622 | value={resolvedActiveBranch} | 638 | value={resolvedActiveBranch} |
| 623 | > | 639 | > |
| 624 | <ComboboxTrigger | 640 | <div className={cn("flex min-w-0 items-center gap-1", className)}> |
| 625 | render={<Button variant="ghost" size="xs" />} | 641 | {branchPr && branchPrStatus ? ( |
| 626 | className={cn("min-w-0 text-muted-foreground/70 hover:text-foreground/80", className)} | 642 | <Tooltip> |
| 627 | disabled={isInitialBranchesLoadPending || isBranchActionPending} | 643 | <TooltipTrigger |
| 628 | > | 644 | render={ |
| 629 | <GitBranchIcon className="size-3 shrink-0 opacity-70" /> | 645 | <button |
| 630 | <span className="min-w-0 max-w-[240px] truncate">{triggerLabel}</span> | 646 | type="button" |
| 631 | <ChevronDownIcon className="size-3 shrink-0 opacity-50" /> | 647 | aria-label={branchPrTooltip} |
| 632 | </ComboboxTrigger> | 648 | onClick={(event) => openPrLink(event, branchPrStatus.url)} |
| | 649 | className={cn( |
| | 650 | "inline-flex shrink-0 items-center gap-0.5 rounded px-1 py-0.5 text-[11px] font-medium tabular-nums transition-colors hover:bg-muted/60", |
| | 651 | branchPrStatus.colorClass, |
| | 652 | )} |
| | 653 | /> |
| | 654 | } |
| | 655 | > |
| | 656 | <ChangeRequestStatusIcon className="size-3" /> |
| | 657 | <span>#{branchPr.number}</span> |
| | 658 | </TooltipTrigger> |
| | 659 | <TooltipPopup side="top">{branchPrTooltip}</TooltipPopup> |
| | 660 | </Tooltip> |
| | 661 | ) : null} |
| | 662 | <ComboboxTrigger |
| | 663 | render={<Button variant="ghost" size="xs" />} |
| | 664 | className="min-w-0 text-muted-foreground/70 hover:text-foreground/80" |
| | 665 | disabled={isInitialBranchesLoadPending || isBranchActionPending} |
| | 666 | > |
| | 667 | <GitBranchIcon className="size-3 shrink-0 opacity-70" /> |
| | 668 | <span className="min-w-0 max-w-[240px] truncate">{triggerLabel}</span> |
| | 669 | <ChevronDownIcon className="size-3 shrink-0 opacity-50" /> |
| | 670 | </ComboboxTrigger> |
| | 671 | </div> |
| 633 | <ComboboxPopup align="end" side="top" className="flex w-80 flex-col"> | 672 | <ComboboxPopup align="end" side="top" className="flex w-80 flex-col"> |
| 634 | <div className="shrink-0 px-3 pt-2.5"> | 673 | <div className="shrink-0 px-3 pt-2.5"> |
| 635 | <div className="relative -translate-y-px border-b border-border/70 pb-1.5 transition-colors focus-within:border-ring"> | 674 | <div className="relative -translate-y-px border-b border-border/70 pb-1.5 transition-colors focus-within:border-ring"> |