Show current branch in Source Control header (#9787)

* feat(source-control): show current branch in header

* fix(source-control): keep header focused on branch

* fix(source-control): compact detached head identity

* fix(source-control): make branch identity keyboard accessible

* fix(source-control): keep create review in checks
This commit is contained in:
Brennan Benson 2026-07-22 13:29:45 -07:00 committed by GitHub
parent 405b9f245a
commit 56a31a5af0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 146 additions and 414 deletions

View File

@ -12,13 +12,15 @@ type DetachedHeadBadgeProps = {
label?: 'sidebar' | 'source-control'
side?: React.ComponentProps<typeof TooltipContent>['side']
className?: string
tabIndex?: number
}
export function DetachedHeadBadge({
display,
label = 'source-control',
side = 'right',
className
className,
tabIndex
}: DetachedHeadBadgeProps): React.JSX.Element {
const visibleLabel = label === 'sidebar' ? display.sidebarLabel : display.sourceControlLabel
@ -27,6 +29,8 @@ export function DetachedHeadBadge({
<TooltipTrigger asChild>
<Badge
variant="outline"
aria-label={display.tooltip}
tabIndex={tabIndex}
className={cn(
'h-[18px] shrink-0 gap-1 rounded px-1.5 text-[10px] font-medium leading-none',
'border-[color:color-mix(in_srgb,var(--git-decoration-modified)_30%,transparent)] bg-[color:color-mix(in_srgb,var(--git-decoration-modified)_8%,transparent)] text-[color:var(--git-decoration-modified)]',
@ -34,7 +38,7 @@ export function DetachedHeadBadge({
)}
>
<GitCommitHorizontal className="size-2.5" />
{visibleLabel}
<span className="min-w-0 truncate">{visibleLabel}</span>
</Badge>
</TooltipTrigger>
<TooltipContent side={side} sideOffset={8}>

View File

@ -1,157 +0,0 @@
import React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { HostedReviewInfo } from '../../../../shared/hosted-review'
import { HostedReviewHeaderLink } from './hosted-review-header-chrome'
const { openHttpLinkMock } = vi.hoisted(() => ({ openHttpLinkMock: vi.fn() }))
vi.mock('@/lib/http-link-routing', () => ({
openHttpLink: openHttpLinkMock,
registerHttpLinkStoreAccessor: vi.fn()
}))
function makeReview(overrides: Partial<HostedReviewInfo> = {}): HostedReviewInfo {
return {
provider: 'github',
number: 2192,
title: 'Open PR in checks',
state: 'open',
url: 'https://github.com/stablyai/orca/pull/2192',
status: 'pending',
updatedAt: '2026-05-17T00:00:00Z',
mergeable: 'UNKNOWN',
...overrides
}
}
type MinimalClickEvent = Pick<
React.MouseEvent<HTMLButtonElement>,
'nativeEvent' | 'stopPropagation'
>
type ClickModifiers = Partial<Pick<MouseEvent, 'metaKey' | 'ctrlKey' | 'shiftKey'>>
function clickEvent(modifiers: ClickModifiers = {}): MinimalClickEvent {
return {
nativeEvent: {
metaKey: modifiers.metaKey ?? false,
ctrlKey: modifiers.ctrlKey ?? false,
shiftKey: modifiers.shiftKey ?? false
} as MouseEvent,
stopPropagation: vi.fn()
}
}
beforeEach(() => {
openHttpLinkMock.mockReset()
})
describe('HostedReviewHeaderLink', () => {
it('opens GitHub PRs in the Checks tab instead of rendering an external link', () => {
const onOpenHostedReviewInChecks = vi.fn()
const element = HostedReviewHeaderLink({
review: makeReview(),
onOpenHostedReviewInChecks
})
const markup = renderToStaticMarkup(element)
expect(markup).toContain('<button')
expect(markup).toContain('PR #2192')
expect(markup).toContain('underline decoration-border underline-offset-2')
expect(markup).not.toContain('href=')
expect(markup).not.toContain('target="_blank"')
expect(markup).not.toContain('system browser')
expect(markup).not.toContain('⌘+click')
const event = clickEvent()
;(element.props.onClick as (event: MinimalClickEvent) => void)(event)
expect(event.stopPropagation).toHaveBeenCalledTimes(1)
expect(onOpenHostedReviewInChecks).toHaveBeenCalledTimes(1)
expect(openHttpLinkMock).not.toHaveBeenCalled()
})
it.each<[string, ClickModifiers]>([
['Cmd-click', { metaKey: true }],
['Ctrl-click', { ctrlKey: true }],
['Shift+Cmd-click', { metaKey: true, shiftKey: true }],
['Shift+Ctrl-click', { ctrlKey: true, shiftKey: true }]
])('opens GitHub PRs in the Checks tab on %s', (_label, modifiers) => {
const onOpenHostedReviewInChecks = vi.fn()
const element = HostedReviewHeaderLink({
review: makeReview(),
onOpenHostedReviewInChecks
})
const event = clickEvent(modifiers)
;(element.props.onClick as (event: MinimalClickEvent) => void)(event)
expect(event.stopPropagation).toHaveBeenCalledTimes(1)
expect(onOpenHostedReviewInChecks).toHaveBeenCalledTimes(1)
expect(openHttpLinkMock).not.toHaveBeenCalled()
})
it('opens GitLab MRs in the Checks tab instead of rendering an external link', () => {
const onOpenHostedReviewInChecks = vi.fn()
const element = HostedReviewHeaderLink({
review: makeReview({
provider: 'gitlab',
number: 31,
url: 'https://gitlab.com/acme/widgets/-/merge_requests/31'
}),
onOpenHostedReviewInChecks
})
const markup = renderToStaticMarkup(element)
expect(markup).toContain('<button')
expect(markup).not.toContain('href=')
expect(markup).toContain('MR #31')
const event = clickEvent()
;(element.props.onClick as (event: MinimalClickEvent) => void)(event)
expect(event.stopPropagation).toHaveBeenCalledTimes(1)
expect(onOpenHostedReviewInChecks).toHaveBeenCalledTimes(1)
expect(openHttpLinkMock).not.toHaveBeenCalled()
})
it.each<[string, ClickModifiers]>([
['Cmd-click', { metaKey: true }],
['Ctrl-click', { ctrlKey: true }],
['Shift+Cmd-click', { metaKey: true, shiftKey: true }],
['Shift+Ctrl-click', { ctrlKey: true, shiftKey: true }]
])('opens GitLab MRs in the Checks tab on %s', (_label, modifiers) => {
const onOpenHostedReviewInChecks = vi.fn()
const element = HostedReviewHeaderLink({
review: makeReview({
provider: 'gitlab',
number: 31,
url: 'https://gitlab.com/acme/widgets/-/merge_requests/31'
}),
onOpenHostedReviewInChecks
})
const event = clickEvent(modifiers)
;(element.props.onClick as (event: MinimalClickEvent) => void)(event)
expect(event.stopPropagation).toHaveBeenCalledTimes(1)
expect(onOpenHostedReviewInChecks).toHaveBeenCalledTimes(1)
expect(openHttpLinkMock).not.toHaveBeenCalled()
})
it('keeps other provider reviews as external hosted-review links', () => {
const markup = renderToStaticMarkup(
<HostedReviewHeaderLink
review={makeReview({
provider: 'bitbucket',
number: 31,
url: 'https://bitbucket.org/acme/widgets/pull-requests/31'
})}
onOpenHostedReviewInChecks={vi.fn()}
/>
)
expect(markup).toContain('<a')
expect(markup).toContain('href="https://bitbucket.org/acme/widgets/pull-requests/31"')
expect(markup).toContain('target="_blank"')
expect(markup).toContain('PR #31')
})
})

View File

@ -45,7 +45,6 @@ import { WORKSPACE_FILE_PATH_MIME } from '@/lib/workspace-file-drag'
import { isFolderRepo } from '../../../../shared/repo-kind'
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@/components/ui/tooltip'
import { Button } from '@/components/ui/button'
import { DetachedHeadBadge } from '@/components/DetachedHeadBadge'
import {
DropdownMenu,
DropdownMenuContent,
@ -265,7 +264,6 @@ import {
resolveCreatePrIntentRemoteStep,
type CreatePrIntentRunToken
} from './source-control-create-pr-intent-flow'
import { resolveVisibleCreatePrHeaderAction } from './source-control-create-pr-intent-state'
import { resolveBlockedCreateReviewNoticeMessage } from './source-control-create-review-blocked-action'
import {
buildLoadingHostedReviewCreationEligibility,
@ -290,7 +288,6 @@ import {
} from './source-control-hosted-review-push-target'
import { buildSourceControlManualReviewUrlFromContext } from './source-control-manual-review-url'
import { parseRemoteRepo } from './source-control-remote-repo'
export { HostedReviewHeaderLink } from './hosted-review-header-chrome'
import {
createRunningCommitMessageGenerationRecord,
getCommitMessageGenerationRecordKey,
@ -809,7 +806,6 @@ function SourceControlInner(): React.JSX.Element {
const activeRepoConnectionId = activeRepo?.connectionId ?? null
const activeRepoExecutionHostId = activeRepo?.executionHostId ?? null
const gitIdentityDisplay = activeWorktree ? getWorktreeGitIdentityDisplay(activeWorktree) : null
const detachedHeadDisplay = gitIdentityDisplay?.kind === 'detached' ? gitIdentityDisplay : null
const branchName = gitIdentityDisplay?.kind === 'branch' ? gitIdentityDisplay.branchName : ''
const entries = useAppStore((s) =>
activeWorktreeId
@ -2806,11 +2802,6 @@ function SourceControlInner(): React.JSX.Element {
]
)
const openHostedReviewInChecks = useCallback(() => {
setRightSidebarOpen(true)
setRightSidebarTab('checks')
}, [setRightSidebarOpen, setRightSidebarTab])
const handleBranchChangedByPullRequestGeneration = useCallback(async (): Promise<void> => {
// Why: AI PR detail generation may rebase before summarizing, so refresh status if HEAD moved before the user submits the draft.
await refreshActiveGitStatusAfterMutation()
@ -4239,10 +4230,6 @@ function SourceControlInner(): React.JSX.Element {
(!createPrHeaderAction.disabled || isCreatingPr || prGenerating)
? createPrHeaderAction
: null
const visibleCreatePrHeaderAction = resolveVisibleCreatePrHeaderAction({
createPrHeaderAction
})
const dropdownItems: DropdownEntry[] = useMemo(
() =>
resolveDropdownItems({
@ -4710,19 +4697,6 @@ function SourceControlInner(): React.JSX.Element {
runCreatePrIntent
])
const handleCreatePrHeaderClick = useCallback((): void => {
if (!createPrHeaderAction || createPrHeaderAction.disabled) {
return
}
if (createPrHeaderAction.kind === 'create_pr') {
void handleCreatePullRequest()
return
}
if (createPrHeaderAction.kind === 'create_pr_intent') {
void runCreatePrIntent()
}
}, [createPrHeaderAction, handleCreatePullRequest, runCreatePrIntent])
const branchCompareInFlightRef = useRef(false)
const branchCompareRerunRef = useRef(false)
const branchCompareRunPromiseRef = useRef<Promise<void> | null>(null)
@ -5452,16 +5426,11 @@ function SourceControlInner(): React.JSX.Element {
<>
<div ref={setSourceControlRoot} className="relative flex h-full flex-col overflow-hidden">
<SourceControlHeaderToolbar
gitIdentityDisplay={gitIdentityDisplay}
filterQuery={filterQuery}
filterExpanded={filterExpanded}
onFilterQueryChange={setFilterQuery}
onFilterExpandedChange={setFilterExpanded}
visibleCreatePrHeaderAction={visibleCreatePrHeaderAction}
hostedReview={hostedReview}
isCreatePrIntentInFlight={isCreatePrIntentInFlight}
isCreatingPr={isCreatingPr || prGenerating}
onCreatePrHeaderClick={handleCreatePrHeaderClick}
onOpenHostedReviewInChecks={openHostedReviewInChecks}
sourceControlViewMode={sourceControlViewMode}
viewModeToggleDisabled={settings === null}
onToggleViewMode={handleToggleSourceControlViewMode}
@ -5476,12 +5445,6 @@ function SourceControlInner(): React.JSX.Element {
manualReviewUrl={manualReviewUrl}
/>
{detachedHeadDisplay && (
<div className="border-b border-border px-3 py-2">
<DetachedHeadBadge display={detachedHeadDisplay} side="bottom" />
</div>
)}
{/* Why: hidden when count is 0 — notes are created from the diff view, so an empty Notes shelf here is pure chrome. */}
{activeWorktreeId && worktreePath && diffCommentCount > 0 && (
<div className="border-b border-border">

View File

@ -1,74 +0,0 @@
import React from 'react'
import { GitMerge } from 'lucide-react'
import type { HostedReviewInfo } from '../../../../shared/hosted-review'
import { cn } from '@/lib/utils'
import { PullRequestIcon } from './checks-panel-content'
function hostedReviewStateClass(review: HostedReviewInfo): string {
if (review.state === 'merged') {
return 'text-purple-500/80'
}
if (review.state === 'open') {
return 'text-emerald-500/80'
}
if (review.state === 'closed') {
return 'text-muted-foreground/60'
}
return 'text-muted-foreground/50'
}
export function HostedReviewIcon({
review,
className
}: {
review: HostedReviewInfo
className?: string
}): React.JSX.Element {
const Icon = review.provider === 'gitlab' ? GitMerge : PullRequestIcon
return <Icon className={cn(className, hostedReviewStateClass(review))} />
}
function hostedReviewLabel(review: HostedReviewInfo): string {
return `${review.provider === 'gitlab' ? 'MR' : 'PR'} #${review.number}`
}
export function HostedReviewHeaderLink({
review,
onOpenHostedReviewInChecks
}: {
review: HostedReviewInfo
onOpenHostedReviewInChecks: () => void
}): React.JSX.Element {
const label = hostedReviewLabel(review)
const className =
'shrink-0 border-0 bg-transparent p-0 text-left font-medium leading-none text-foreground underline decoration-border underline-offset-2 opacity-80 hover:text-foreground hover:decoration-foreground'
if (review.provider === 'github' || review.provider === 'gitlab') {
return (
<button
type="button"
className={className}
onClick={(e) => {
e.stopPropagation()
// Why: GitHub PR and GitLab MR details live in Orca's Checks tab; keep
// the sidebar workflow in-app instead of opening the browser.
onOpenHostedReviewInChecks()
}}
>
{label}
</button>
)
}
return (
<a
href={review.url}
target="_blank"
rel="noreferrer"
className={className}
onClick={(e) => e.stopPropagation()}
>
{label}
</a>
)
}

View File

@ -1,43 +0,0 @@
import { describe, expect, it } from 'vitest'
import { resolveVisibleCreatePrHeaderAction } from './source-control-create-pr-intent-state'
import type { PrimaryAction } from './source-control-primary-action-types'
const disabledCreatePrAction: PrimaryAction = {
kind: 'create_pr',
label: 'Create PR',
title: 'Publish commits before creating a pull request.',
disabled: true
}
const enabledCreatePrAction: PrimaryAction = {
kind: 'create_pr',
label: 'Create PR',
title: 'Create a pull request for this branch',
disabled: false
}
describe('resolveVisibleCreatePrHeaderAction', () => {
it('returns null when no header action is available', () => {
expect(
resolveVisibleCreatePrHeaderAction({
createPrHeaderAction: null
})
).toBeNull()
})
it('keeps a disabled Create PR header visible as a stable toolbar anchor', () => {
expect(
resolveVisibleCreatePrHeaderAction({
createPrHeaderAction: disabledCreatePrAction
})
).toEqual(disabledCreatePrAction)
})
it('keeps an enabled Create PR header visible even when the body composer is open', () => {
expect(
resolveVisibleCreatePrHeaderAction({
createPrHeaderAction: enabledCreatePrAction
})
).toEqual(enabledCreatePrAction)
})
})

View File

@ -1,4 +1,3 @@
import type { PrimaryAction } from './source-control-primary-action-types'
import {
resolveCreateReviewIntentEligibility,
type CreateReviewIntentEligibility,
@ -11,13 +10,3 @@ export type CreatePrIntentKind = CreateReviewIntentKind
export type CreatePrIntentEligibility = CreateReviewIntentEligibility
export const resolveCreatePrIntentEligibility = resolveCreateReviewIntentEligibility
export function resolveVisibleCreatePrHeaderAction({
createPrHeaderAction
}: {
createPrHeaderAction: PrimaryAction | null
}): PrimaryAction | null {
// Why: keep a stable header anchor; disable Create PR when the branch is not
// ready instead of hiding it and shifting the toolbar layout.
return createPrHeaderAction
}

View File

@ -0,0 +1,90 @@
import { renderToStaticMarkup } from 'react-dom/server'
import type { ReactNode } from 'react'
import { describe, expect, it, vi } from 'vitest'
import type { WorktreeGitIdentityDisplay } from '@/lib/worktree-git-identity-display'
import { SourceControlHeaderToolbar } from './source-control-header-toolbar'
vi.mock('@/components/ui/tooltip', () => ({
Tooltip: ({ children }: { children: ReactNode }) => <>{children}</>,
TooltipContent: ({ children }: { children: ReactNode }) => <>{children}</>,
TooltipTrigger: ({ children }: { children: ReactNode }) => <>{children}</>
}))
vi.mock('./source-control-header-overflow-menu', () => ({
SourceControlHeaderOverflowMenu: () => <button type="button">More actions</button>
}))
vi.mock('./source-control-branch-context-row', () => ({
shouldShowSourceControlBranchContextRow: () => false,
SourceControlBranchContextRow: () => null
}))
function renderToolbar(
gitIdentityDisplay: WorktreeGitIdentityDisplay | null = {
kind: 'branch',
branchName: 'brennanb2025/source-control-branch-name'
}
): string {
return renderToStaticMarkup(
<SourceControlHeaderToolbar
gitIdentityDisplay={gitIdentityDisplay}
filterQuery=""
filterExpanded={false}
onFilterQueryChange={vi.fn()}
onFilterExpandedChange={vi.fn()}
sourceControlViewMode="list"
viewModeToggleDisabled={false}
onToggleViewMode={vi.fn()}
onChangeBaseRef={vi.fn()}
onRefreshBranchCompare={vi.fn()}
branchCompareRefreshDisabled={false}
diffCommentCount={0}
onExpandNotes={vi.fn()}
branchSummary={null}
compareBaseRef={null}
/>
)
}
describe('SourceControlHeaderToolbar', () => {
it('renders the truncating branch identity before source control actions', () => {
const markup = renderToolbar()
const branchIndex = markup.indexOf('brennanb2025/source-control-branch-name')
const filterIndex = markup.indexOf('data-testid="source-control-filter-toggle"')
expect(branchIndex).toBeGreaterThan(-1)
expect(filterIndex).toBeGreaterThan(branchIndex)
expect(markup).toContain('aria-label="Current branch: brennanb2025/source-control-branch-name"')
expect(markup).toContain('tabindex="0"')
expect(markup).toContain('min-w-0 truncate')
expect(markup).not.toContain('Create PR')
})
it('renders detached HEAD in the same identity slot', () => {
const markup = renderToolbar({
kind: 'detached',
shortHead: '8cec248',
sidebarLabel: 'Detached HEAD @ 8cec248',
sourceControlLabel: 'Detached HEAD · 8cec248',
tooltip: 'Detached HEAD at 8cec248. You are viewing a commit, not a branch.'
})
const identityIndex = markup.indexOf('Detached HEAD · 8cec248')
const filterIndex = markup.indexOf('data-testid="source-control-filter-toggle"')
expect(markup).not.toContain('aria-label="Current branch:')
expect(identityIndex).toBeGreaterThan(-1)
expect(filterIndex).toBeGreaterThan(identityIndex)
expect(markup).toContain(
'aria-label="Detached HEAD at 8cec248. You are viewing a commit, not a branch."'
)
expect(markup).toContain('tabindex="0"')
expect(markup).toContain('lucide-git-commit-horizontal')
})
it('keeps the identity slot empty until git identity is known', () => {
const markup = renderToolbar(null)
expect(markup).not.toContain('aria-label="Current branch:')
expect(markup).not.toContain('Detached HEAD')
})
})

View File

@ -1,17 +1,16 @@
import React, { useCallback, useEffect, useRef } from 'react'
import { GitPullRequestArrow, Loader2, Search, X } from 'lucide-react'
import { GitBranch, Search, X } from 'lucide-react'
import type {
GitBranchCompareSummary,
GitUpstreamStatus,
SourceControlViewMode
} from '../../../../shared/types'
import type { HostedReviewInfo } from '../../../../shared/hosted-review'
import type { PrimaryAction } from './source-control-primary-action'
import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { cn } from '@/lib/utils'
import { translate } from '@/i18n/i18n'
import { HostedReviewHeaderLink, HostedReviewIcon } from './hosted-review-header-chrome'
import { DetachedHeadBadge } from '@/components/DetachedHeadBadge'
import type { WorktreeGitIdentityDisplay } from '@/lib/worktree-git-identity-display'
import {
shouldShowSourceControlBranchContextRow,
SourceControlBranchContextRow
@ -19,16 +18,11 @@ import {
import { SourceControlHeaderOverflowMenu } from './source-control-header-overflow-menu'
type SourceControlHeaderToolbarProps = {
gitIdentityDisplay: WorktreeGitIdentityDisplay | null
filterQuery: string
filterExpanded: boolean
onFilterQueryChange: (value: string) => void
onFilterExpandedChange: (expanded: boolean) => void
visibleCreatePrHeaderAction: PrimaryAction | null
hostedReview: HostedReviewInfo | null
isCreatePrIntentInFlight: boolean
isCreatingPr: boolean
onCreatePrHeaderClick: () => void
onOpenHostedReviewInChecks: () => void
sourceControlViewMode: SourceControlViewMode
viewModeToggleDisabled: boolean
onToggleViewMode: () => void
@ -43,65 +37,45 @@ type SourceControlHeaderToolbarProps = {
manualReviewUrl?: string | null
}
function HostedReviewToolbarLink({
review,
onOpenHostedReviewInChecks,
compact
function SourceControlGitIdentityLabel({
display
}: {
review: HostedReviewInfo
onOpenHostedReviewInChecks: () => void
compact?: boolean
display: WorktreeGitIdentityDisplay
}): React.JSX.Element {
return (
<div
className={cn(
'flex min-w-0 items-center gap-1 text-[11.5px] leading-none',
compact ? 'max-w-[72px] shrink-0' : 'flex-1'
)}
>
<HostedReviewIcon review={review} className="size-3 shrink-0" />
<HostedReviewHeaderLink
review={review}
onOpenHostedReviewInChecks={onOpenHostedReviewInChecks}
/>
</div>
)
}
if (display.kind === 'detached') {
return (
<span className="flex min-w-0 flex-1 items-center">
<DetachedHeadBadge
display={display}
side="bottom"
className="min-w-0 max-w-full shrink"
tabIndex={0}
/>
</span>
)
}
const branchName = display.branchName
const label = translate(
'auto.components.right.sidebar.SourceControl.a4e93c21d7',
'Current branch: {{value0}}',
{ value0: branchName }
)
function CreatePrHeaderButton({
action,
isCreatePrIntentInFlight,
isCreatingPr,
onClick
}: {
action: PrimaryAction
isCreatePrIntentInFlight: boolean
isCreatingPr: boolean
onClick: () => void
}): React.JSX.Element {
return (
<Tooltip>
<TooltipTrigger asChild>
<span className="inline-flex shrink-0">
<Button
type="button"
size="xs"
disabled={action.disabled}
onClick={onClick}
className="h-6 shrink-0 px-2 text-[11px]"
title={action.title}
>
{isCreatePrIntentInFlight || isCreatingPr ? (
<Loader2 className="size-3.5 animate-spin" />
) : (
<GitPullRequestArrow className="size-3.5" aria-hidden="true" />
)}
{action.label}
</Button>
<span
className="flex min-w-0 flex-1 items-center gap-1 rounded-sm font-mono text-xs font-medium leading-none text-foreground/90 outline-none focus-visible:ring-1 focus-visible:ring-ring"
aria-label={label}
tabIndex={0}
>
<GitBranch className="size-3 shrink-0 text-muted-foreground" aria-hidden="true" />
<span className="min-w-0 truncate">{branchName}</span>
</span>
</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={6} className="max-w-72">
{action.title}
<TooltipContent side="bottom" sideOffset={6} className="max-w-72 break-all font-mono">
{branchName}
</TooltipContent>
</Tooltip>
)
@ -124,16 +98,11 @@ function renderOverflowMenu(
}
export function SourceControlHeaderToolbar({
gitIdentityDisplay,
filterQuery,
filterExpanded,
onFilterQueryChange,
onFilterExpandedChange,
visibleCreatePrHeaderAction,
hostedReview,
isCreatePrIntentInFlight,
isCreatingPr,
onCreatePrHeaderClick,
onOpenHostedReviewInChecks,
sourceControlViewMode,
viewModeToggleDisabled,
onToggleViewMode,
@ -196,25 +165,11 @@ export function SourceControlHeaderToolbar({
>
{showCollapsedToolbar ? (
<>
{hostedReview ? (
<HostedReviewToolbarLink
review={hostedReview}
onOpenHostedReviewInChecks={onOpenHostedReviewInChecks}
/>
) : visibleCreatePrHeaderAction ? (
<CreatePrHeaderButton
action={visibleCreatePrHeaderAction}
isCreatePrIntentInFlight={isCreatePrIntentInFlight}
isCreatingPr={isCreatingPr}
onClick={onCreatePrHeaderClick}
/>
{gitIdentityDisplay ? (
<SourceControlGitIdentityLabel display={gitIdentityDisplay} />
) : (
<span className="min-w-0 flex-1" aria-hidden="true" />
)}
{visibleCreatePrHeaderAction && !hostedReview ? (
// Why: keep filter/overflow pinned right without stretching Create PR.
<span className="min-w-0 flex-1" aria-hidden="true" />
) : null}
<button
type="button"
data-testid="source-control-filter-toggle"
@ -237,7 +192,7 @@ export function SourceControlHeaderToolbar({
) : (
<>
{/* Why: expanded filter owns the toolbar row so typing isn't squeezed
beside PR links or overflow actions collapse to reach those. */}
beside branch identity or header actions collapse to reach those. */}
<div className="flex min-w-0 w-full flex-1 items-center gap-1.5">
<Search className="size-3.5 shrink-0 text-muted-foreground" />
<input

View File

@ -9789,7 +9789,8 @@
"834cb3f23d": "Fix with AI",
"783a808870": "Close"
},
"97e7124eac": "Could not refresh Source Control. Try again."
"97e7124eac": "Could not refresh Source Control. Try again.",
"a4e93c21d7": "Current branch: {{value0}}"
},
"SourceControlAgentActionDialog": {
"8e856842d1": "Could not start the selected agent.",

View File

@ -9766,7 +9766,8 @@
"834cb3f23d": "Corregir con AI",
"783a808870": "Cerrar"
},
"97e7124eac": "No se pudo actualizar Source Control. Vuelve a intentarlo."
"97e7124eac": "No se pudo actualizar Source Control. Vuelve a intentarlo.",
"a4e93c21d7": "Rama actual: {{value0}}"
},
"SourceControlAgentActionDialog": {
"8e856842d1": "No se pudo iniciar el agente seleccionado.",

View File

@ -9766,7 +9766,8 @@
"834cb3f23d": "AIで修正",
"783a808870": "閉じる"
},
"97e7124eac": "Source Control を更新できませんでした。もう一度お試しください。"
"97e7124eac": "Source Control を更新できませんでした。もう一度お試しください。",
"a4e93c21d7": "現在のブランチ: {{value0}}"
},
"SourceControlAgentActionDialog": {
"8e856842d1": "選択した agent を開始できませんでした。",

View File

@ -9766,7 +9766,8 @@
"834cb3f23d": "AI로 수정",
"783a808870": "닫기"
},
"97e7124eac": "Source Control을 새로 고칠 수 없습니다. 다시 시도하세요."
"97e7124eac": "Source Control을 새로 고칠 수 없습니다. 다시 시도하세요.",
"a4e93c21d7": "현재 브랜치: {{value0}}"
},
"SourceControlAgentActionDialog": {
"8e856842d1": "선택한 agent를 시작할 수 없습니다.",

View File

@ -9766,7 +9766,8 @@
"834cb3f23d": "使用 AI 修复",
"783a808870": "关闭"
},
"97e7124eac": "无法刷新 Source Control。请重试。"
"97e7124eac": "无法刷新 Source Control。请重试。",
"a4e93c21d7": "当前分支:{{value0}}"
},
"SourceControlAgentActionDialog": {
"8e856842d1": "无法启动选定的智能体。",