@@ -29,6 +29,7 @@ import { ArrowPathIcon } from './icons/ArrowPathIcon';
2929import { ArrowUpIcon } from './icons/ArrowUpIcon' ;
3030import { ArrowDownIcon } from './icons/ArrowDownIcon' ;
3131import BranchSelectionModal from './modals/BranchSelectionModal' ;
32+ import { getDisplayBranchName , getRemoteBranchesToOffer , getMainBranchDetails , normalizeBranchForComparison } from '../utils/branchHelpers' ;
3233
3334
3435interface RepositoryCardProps {
@@ -74,50 +75,62 @@ const BranchSwitcher: React.FC<{
7475 repoId : string ;
7576 repoName : string ;
7677 branchInfo : BranchInfo | null ;
78+ vcs : VcsType ;
7779 onSwitchBranch : ( repoId : string , branch : string ) => void ;
7880 isOpen : boolean ;
7981 onToggle : ( ) => void ;
8082 onClose : ( ) => void ;
8183 onRefreshBranches : ( ) => Promise < void > | void ;
82- } > = ( { repoId, repoName, branchInfo, onSwitchBranch, isOpen, onToggle, onClose, onRefreshBranches } ) => {
84+ } > = ( { repoId, repoName, branchInfo, vcs , onSwitchBranch, isOpen, onToggle, onClose, onRefreshBranches } ) => {
8385 const buttonRef = useRef < HTMLButtonElement > ( null ) ;
8486 const dropdownRef = useRef < HTMLDivElement > ( null ) ;
8587 const [ dropdownStyle , setDropdownStyle ] = useState < React . CSSProperties > ( { } ) ;
8688 const [ isModalOpen , setIsModalOpen ] = useState ( false ) ;
8789 const [ isRefreshingBranches , setIsRefreshingBranches ] = useState ( false ) ;
8890
8991 const localBranches = branchInfo ?. local ?? [ ] ;
90- const remoteBranches = branchInfo ?. remote ?? [ ] ;
91- const currentBranch = branchInfo ?. current ?? '' ;
92-
93- const remoteMainBranch = remoteBranches . find ( branch => branch . split ( '/' ) . slice ( - 1 ) [ 0 ] === 'main' ) ;
94- const hasLocalMainBranch = localBranches . includes ( 'main' ) ;
95- const mainBranchTarget = hasLocalMainBranch ? 'main' : remoteMainBranch ;
96- const showMainBranchButton = Boolean ( mainBranchTarget && currentBranch !== 'main' ) ;
97-
98- const remoteBranchesToOffer = remoteBranches . filter ( rBranch => {
99- const localEquivalent = rBranch . split ( '/' ) . slice ( 1 ) . join ( '/' ) ;
100- return ! localBranches . includes ( localEquivalent ) ;
101- } ) ;
92+ const remoteBranchesToOffer = branchInfo ? getRemoteBranchesToOffer ( branchInfo , vcs ) : [ ] ;
93+ const currentBranch = branchInfo ?. current ?? null ;
94+ const normalizedCurrent = currentBranch ? normalizeBranchForComparison ( currentBranch , vcs ) : null ;
95+
96+ const otherLocalBranches = branchInfo
97+ ? localBranches . filter ( branch => {
98+ if ( ! normalizedCurrent ) {
99+ return true ;
100+ }
101+ return normalizeBranchForComparison ( branch , vcs ) !== normalizedCurrent ;
102+ } )
103+ : [ ] ;
102104
103- const otherLocalBranches = localBranches . filter ( b => b !== currentBranch ) ;
104105 const hasOptions = otherLocalBranches . length > 0 || remoteBranchesToOffer . length > 0 ;
105106
107+ const currentBranchLabel = currentBranch ? getDisplayBranchName ( currentBranch , vcs ) : 'Unknown' ;
106108 const branchDropdownTooltip = useTooltip (
107109 branchInfo
108- ? ( currentBranch ? `Current branch: ${ currentBranch } ` : 'Branch name unavailable' )
110+ ? ( currentBranch ? `Current branch: ${ currentBranchLabel } ` : 'Branch name unavailable' )
109111 : 'Branch information unavailable'
110112 ) ;
111113 const branchSearchTooltip = useTooltip (
112114 isRefreshingBranches ? 'Refreshing branches…' : 'Search all branches'
113115 ) ;
116+ const mainBranchDetails = branchInfo ? getMainBranchDetails ( branchInfo , vcs ) : null ;
117+ const showMainBranchButton = Boolean (
118+ mainBranchDetails && ( ! normalizedCurrent || normalizeBranchForComparison ( mainBranchDetails . target , vcs ) !== normalizedCurrent )
119+ ) ;
114120 const mainBranchTooltip = useTooltip (
115- mainBranchTarget
116- ? hasLocalMainBranch
117- ? 'Switch to the main branch'
118- : 'Track and switch to the remote main branch'
119- : 'Main branch not available'
121+ mainBranchDetails
122+ ? vcs === VcsType . Git
123+ ? mainBranchDetails . scope === 'local'
124+ ? 'Switch to the main branch'
125+ : 'Track and switch to the remote main branch'
126+ : mainBranchDetails . scope === 'local'
127+ ? 'Switch to trunk'
128+ : 'Switch working copy to trunk'
129+ : vcs === VcsType . Git
130+ ? 'Main branch not available'
131+ : 'Trunk not available'
120132 ) ;
133+ const mainBranchAriaLabel = vcs === VcsType . Git ? 'Switch to main branch' : 'Switch to trunk' ;
121134
122135 useEffect ( ( ) => {
123136 if ( isOpen && buttonRef . current ) {
@@ -171,8 +184,8 @@ const BranchSwitcher: React.FC<{
171184 } ;
172185
173186 const handleSwitchToMain = ( ) => {
174- if ( ! mainBranchTarget ) return ;
175- onSwitchBranch ( repoId , mainBranchTarget ) ;
187+ if ( ! mainBranchDetails ) return ;
188+ onSwitchBranch ( repoId , mainBranchDetails . target ) ;
176189 onClose ( ) ;
177190 } ;
178191
@@ -213,7 +226,7 @@ const BranchSwitcher: React.FC<{
213226 className = "block w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700"
214227 role = "menuitem"
215228 >
216- { branch }
229+ { getDisplayBranchName ( branch , vcs ) }
217230 </ button >
218231 ) ) }
219232 { remoteBranchesToOffer . length > 0 && < div className = "px-4 py-2 text-xs font-bold text-gray-500 uppercase border-t border-gray-200 dark:border-gray-700" > Remote</ div > }
@@ -225,7 +238,7 @@ const BranchSwitcher: React.FC<{
225238 className = "block w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700"
226239 role = "menuitem"
227240 >
228- { branch }
241+ { getDisplayBranchName ( branch , vcs ) }
229242 </ button >
230243 )
231244 } ) }
@@ -246,7 +259,7 @@ const BranchSwitcher: React.FC<{
246259 aria-haspopup = "true"
247260 aria-expanded = { isOpen }
248261 >
249- < span className = "truncate max-w-[150px] sm:max-w-[200px]" > { currentBranch } </ span >
262+ < span className = "truncate max-w-[150px] sm:max-w-[200px]" > { currentBranchLabel } </ span >
250263 < ChevronDownIcon className = { `ml-1 -mr-1 h-4 w-4 transition-transform ${ isOpen ? 'rotate-180' : '' } ` } />
251264 </ button >
252265 </ div >
@@ -270,7 +283,7 @@ const BranchSwitcher: React.FC<{
270283 type = "button"
271284 onClick = { handleSwitchToMain }
272285 className = "flex-shrink-0 p-1.5 rounded-md text-gray-500 hover:text-green-600 dark:text-gray-300 dark:hover:text-green-400 hover:bg-green-50 dark:hover:bg-green-900/40 focus:outline-none focus:ring-2 focus:ring-green-500"
273- aria-label = "Switch to main branch"
286+ aria-label = { mainBranchAriaLabel }
274287 >
275288 < HomeIcon className = "h-4 w-4" />
276289 </ button >
@@ -281,6 +294,7 @@ const BranchSwitcher: React.FC<{
281294 isOpen = { isModalOpen }
282295 repositoryName = { repoName }
283296 branchInfo = { branchInfo }
297+ vcs = { vcs }
284298 onSelectBranch = { handleModalSelect }
285299 onClose = { closeModal }
286300 />
@@ -656,25 +670,21 @@ const RepositoryCard: React.FC<RepositoryCardProps> = ({
656670 < div className = "flex items-center justify-between" >
657671 < div className = "flex items-center min-w-0" >
658672 { vcs === VcsType . Git ? (
659- < >
660- < GitBranchIcon className = "h-4 w-4 mr-2 text-gray-400 dark:text-gray-500 flex-shrink-0" />
661- < BranchSwitcher
662- isOpen = { isDropdownOpen }
663- onToggle = { toggleDropdown }
664- onClose = { closeDropdown }
665- repoId = { id }
666- repoName = { name }
667- branchInfo = { branchInfo }
668- onSwitchBranch = { onSwitchBranch }
669- onRefreshBranches = { ( ) => onRefreshRepoState ( id ) }
670- />
671- </ >
673+ < GitBranchIcon className = "h-4 w-4 mr-2 text-gray-400 dark:text-gray-500 flex-shrink-0" />
672674 ) : (
673- < >
674- < SvnIcon className = "h-4 w-4 mr-2 text-gray-400 dark:text-gray-500 flex-shrink-0" />
675- < span className = "truncate" > SVN Repository</ span >
676- </ >
675+ < SvnIcon className = "h-4 w-4 mr-2 text-gray-400 dark:text-gray-500 flex-shrink-0" />
677676 ) }
677+ < BranchSwitcher
678+ isOpen = { isDropdownOpen }
679+ onToggle = { toggleDropdown }
680+ onClose = { closeDropdown }
681+ repoId = { id }
682+ repoName = { name }
683+ branchInfo = { branchInfo }
684+ vcs = { vcs }
685+ onSwitchBranch = { onSwitchBranch }
686+ onRefreshBranches = { ( ) => onRefreshRepoState ( id ) }
687+ />
678688 </ div >
679689 < div className = "flex-shrink-0 ml-4" >
680690 { isPathValid && detailedStatus && < StatusIndicator status = { detailedStatus } /> }
0 commit comments