@@ -377,6 +377,15 @@ import { BranchPruner } from './helpers/branch-pruner'
377377import { createTutorialRepository } from './helpers/create-tutorial-repository'
378378import { findRemoteBranchName } from './helpers/find-branch-name'
379379import { RepositoryIndicatorUpdater } from './helpers/repository-indicator-updater'
380+ import {
381+ createInitialLoadingSidebarState ,
382+ createLoadedSidebarState ,
383+ createLoadingSidebarState ,
384+ createSidebarStateFromStatus ,
385+ findSidebarWorktreeStateRepository ,
386+ getCurrentWorktreeEntryForRepository ,
387+ shouldRefreshSidebarWorktrees ,
388+ } from './helpers/sidebar-worktrees'
380389import { OnboardingTutorialAssessor } from './helpers/tutorial-assessor'
381390import {
382391 getNotificationsEnabled ,
@@ -471,6 +480,7 @@ const shellKey = 'shell'
471480
472481const showRecentRepositoriesKey = 'show-recent-repositories'
473482const showWorktreesKey = 'show-worktrees'
483+ const showWorktreesInSidebarKey = 'show-worktrees-in-sidebar'
474484const showCompareTabKey = 'show-compare-tab'
475485const showCompareTabDefault = true
476486const repositoryIndicatorsEnabledKey = 'enable-repository-indicators'
@@ -641,6 +651,8 @@ export class AppStore extends TypedBaseStore<IAppState> {
641651 private titleBarStyle : TitleBarStyle = 'native'
642652 private showRecentRepositories : boolean = true
643653 private showWorktrees : boolean = false
654+ private showWorktreesInSidebar : boolean = false
655+ private readonly lastSidebarWorktreeRefreshAt = new Map < string , number > ( )
644656 private showCompareTab : boolean = showCompareTabDefault
645657 private hideWindowOnQuit : boolean = __DARWIN__
646658
@@ -762,6 +774,8 @@ export class AppStore extends TypedBaseStore<IAppState> {
762774
763775 this . showRecentRepositories = getBoolean ( showRecentRepositoriesKey ) ?? true
764776 this . showWorktrees = getBoolean ( showWorktreesKey ) ?? false
777+ this . showWorktreesInSidebar =
778+ this . showWorktrees && ( getBoolean ( showWorktreesInSidebarKey ) ?? false )
765779 this . showCompareTab = getBoolean ( showCompareTabKey , showCompareTabDefault )
766780
767781 this . repositoryIndicatorUpdater = new RepositoryIndicatorUpdater (
@@ -1034,6 +1048,9 @@ export class AppStore extends TypedBaseStore<IAppState> {
10341048 this . repositoriesStore . onDidUpdate ( updateRepositories => {
10351049 this . repositories = updateRepositories
10361050 this . updateRepositorySelectionAfterRepositoriesChanged ( )
1051+ if ( this . showWorktreesInSidebar ) {
1052+ void this . preloadSidebarWorktrees ( )
1053+ }
10371054 this . emitUpdate ( )
10381055 } )
10391056
@@ -1215,6 +1232,7 @@ export class AppStore extends TypedBaseStore<IAppState> {
12151232 titleBarStyle : this . titleBarStyle ,
12161233 showRecentRepositories : this . showRecentRepositories ,
12171234 showWorktrees : this . showWorktrees ,
1235+ showWorktreesInSidebar : this . showWorktreesInSidebar ,
12181236 showCompareTab : this . showCompareTab ,
12191237 apiRepositories : this . apiRepositoriesStore . getState ( ) ,
12201238 useWindowsOpenSSH : this . useWindowsOpenSSH ,
@@ -2463,6 +2481,9 @@ export class AppStore extends TypedBaseStore<IAppState> {
24632481 this . repositories = repositories
24642482
24652483 this . updateRepositorySelectionAfterRepositoriesChanged ( )
2484+ if ( this . showWorktreesInSidebar ) {
2485+ void this . preloadSidebarWorktrees ( )
2486+ }
24662487
24672488 this . sidebarWidth = constrain (
24682489 getNumber ( sidebarWidthConfigKey , defaultSidebarWidth )
@@ -3959,6 +3980,10 @@ export class AppStore extends TypedBaseStore<IAppState> {
39593980
39603981 const state = this . repositoryStateCache . get ( repository )
39613982 const gitStore = this . gitStoreCache . get ( repository )
3983+ const sidebarRepository = findSidebarWorktreeStateRepository (
3984+ this . repositories ,
3985+ repository
3986+ )
39623987
39633988 // if we cannot get a valid status it's a good indicator that the repository
39643989 // is in a bad state - let's mark it as missing here and give up on the
@@ -3971,10 +3996,43 @@ export class AppStore extends TypedBaseStore<IAppState> {
39713996 return
39723997 }
39733998
3999+ if ( this . showWorktreesInSidebar ) {
4000+ const existing = this . localRepositoryStateLookup . get ( sidebarRepository . id )
4001+ this . localRepositoryStateLookup . set (
4002+ sidebarRepository . id ,
4003+ createLoadingSidebarState ( sidebarRepository , status , existing )
4004+ )
4005+ this . emitUpdate ( )
4006+ }
4007+
39744008 // loadBranches needs the default remote to determine the default branch
39754009 await gitStore . loadRemotes ( )
39764010 await gitStore . loadBranches ( )
39774011 await gitStore . loadWorktrees ( )
4012+ this . repositoryStateCache . updateWorktreesState ( repository , ( ) => ( {
4013+ allWorktrees : gitStore . allWorktrees ,
4014+ currentWorktree : gitStore . currentWorktree ,
4015+ } ) )
4016+ if ( sidebarRepository !== repository ) {
4017+ this . repositoryStateCache . updateWorktreesState ( sidebarRepository , ( ) => ( {
4018+ allWorktrees : gitStore . allWorktrees ,
4019+ currentWorktree : getCurrentWorktreeEntryForRepository (
4020+ gitStore . allWorktrees ,
4021+ sidebarRepository
4022+ ) ,
4023+ } ) )
4024+ }
4025+ this . lastSidebarWorktreeRefreshAt . set ( repository . hash , Date . now ( ) )
4026+ this . lastSidebarWorktreeRefreshAt . set ( sidebarRepository . hash , Date . now ( ) )
4027+ this . updateSidebarIndicator ( repository , status )
4028+ const refreshed = this . localRepositoryStateLookup . get ( sidebarRepository . id )
4029+ if ( refreshed !== undefined ) {
4030+ this . localRepositoryStateLookup . set (
4031+ sidebarRepository . id ,
4032+ createLoadedSidebarState ( refreshed , gitStore . allWorktrees )
4033+ )
4034+ }
4035+ this . emitUpdate ( )
39784036
39794037 const section = state . selectedSection
39804038 let refreshSectionPromise : Promise < void >
@@ -4026,6 +4084,58 @@ export class AppStore extends TypedBaseStore<IAppState> {
40264084 }
40274085 }
40284086
4087+ private async preloadSidebarWorktrees ( ) {
4088+ for ( const repository of this . repositories ) {
4089+ if ( repository . isLinkedWorktree ) {
4090+ continue
4091+ }
4092+
4093+ const existing = this . localRepositoryStateLookup . get ( repository . id )
4094+ this . localRepositoryStateLookup . set (
4095+ repository . id ,
4096+ createInitialLoadingSidebarState ( repository , existing )
4097+ )
4098+ }
4099+ this . emitUpdate ( )
4100+
4101+ for ( const repository of this . repositories ) {
4102+ if ( repository . isLinkedWorktree ) {
4103+ continue
4104+ }
4105+
4106+ const exists = await pathExists ( repository . path )
4107+ if ( ! exists ) {
4108+ continue
4109+ }
4110+
4111+ try {
4112+ const gitStore = this . gitStoreCache . get ( repository )
4113+ await gitStore . loadWorktrees ( )
4114+ this . repositoryStateCache . updateWorktreesState ( repository , ( ) => ( {
4115+ allWorktrees : gitStore . allWorktrees ,
4116+ currentWorktree : gitStore . currentWorktree ,
4117+ } ) )
4118+
4119+ const existing = this . localRepositoryStateLookup . get ( repository . id )
4120+ if ( existing !== undefined ) {
4121+ this . localRepositoryStateLookup . set (
4122+ repository . id ,
4123+ createLoadedSidebarState ( existing , gitStore . allWorktrees )
4124+ )
4125+ }
4126+ this . lastSidebarWorktreeRefreshAt . set ( repository . hash , Date . now ( ) )
4127+ this . emitUpdate ( )
4128+ } catch ( error ) {
4129+ log . warn (
4130+ `[AppStore] Failed to preload sidebar worktrees for '${ nameOf (
4131+ repository
4132+ ) } '`,
4133+ error
4134+ )
4135+ }
4136+ }
4137+ }
4138+
40294139 private async updateStashEntryCountMetric (
40304140 repository : Repository ,
40314141 desktopStashEntryCount : number ,
@@ -4065,12 +4175,16 @@ export class AppStore extends TypedBaseStore<IAppState> {
40654175 return
40664176 }
40674177
4068- lookup . set ( repository . id , {
4069- aheadBehind : status . branchAheadBehind || null ,
4070- changedFilesCount : status . workingDirectory . files . length ,
4071- branchName : status . currentBranch || null ,
4072- defaultBranchName : repository . defaultBranch ,
4073- } )
4178+ lookup . set (
4179+ repository . id ,
4180+ createSidebarStateFromStatus (
4181+ repository ,
4182+ status ,
4183+ lookup . get ( repository . id ) ,
4184+ this . repositoryStateCache . get ( repository ) . worktreesState . allWorktrees ,
4185+ this . showWorktreesInSidebar
4186+ )
4187+ )
40744188 }
40754189 /**
40764190 * Refresh indicator in repository list for a specific repository
@@ -4096,6 +4210,37 @@ export class AppStore extends TypedBaseStore<IAppState> {
40964210 return
40974211 }
40984212
4213+ if (
4214+ this . showWorktreesInSidebar &&
4215+ ! repository . isLinkedWorktree &&
4216+ shouldRefreshSidebarWorktrees (
4217+ this . lastSidebarWorktreeRefreshAt . get ( repository . hash ) ,
4218+ this . repositoryStateCache . get ( repository ) . worktreesState . allWorktrees
4219+ )
4220+ ) {
4221+ this . updateSidebarIndicator ( repository , status )
4222+ const existing = lookup . get ( repository . id )
4223+ lookup . set (
4224+ repository . id ,
4225+ createLoadingSidebarState ( repository , status , existing )
4226+ )
4227+ this . emitUpdate ( )
4228+
4229+ await gitStore . loadWorktrees ( )
4230+ this . repositoryStateCache . updateWorktreesState ( repository , ( ) => ( {
4231+ allWorktrees : gitStore . allWorktrees ,
4232+ currentWorktree : gitStore . currentWorktree ,
4233+ } ) )
4234+ const refreshed = lookup . get ( repository . id )
4235+ if ( refreshed !== undefined ) {
4236+ lookup . set (
4237+ repository . id ,
4238+ createLoadedSidebarState ( refreshed , gitStore . allWorktrees )
4239+ )
4240+ }
4241+ this . lastSidebarWorktreeRefreshAt . set ( repository . hash , Date . now ( ) )
4242+ }
4243+
40994244 this . updateSidebarIndicator ( repository , status )
41004245 this . emitUpdate ( )
41014246
@@ -4117,6 +4262,8 @@ export class AppStore extends TypedBaseStore<IAppState> {
41174262 changedFilesCount : existing ?. changedFilesCount ?? 0 ,
41184263 branchName : existing ?. branchName ?? null ,
41194264 defaultBranchName : existing ?. defaultBranchName ?? null ,
4265+ isLoadingWorktrees : existing ?. isLoadingWorktrees ?? false ,
4266+ allWorktrees : existing ?. allWorktrees ?? [ ] ,
41204267 } )
41214268 this . emitUpdate ( )
41224269 }
@@ -4191,10 +4338,30 @@ export class AppStore extends TypedBaseStore<IAppState> {
41914338 }
41924339 setBoolean ( showWorktreesKey , showWorktrees )
41934340 this . showWorktrees = showWorktrees
4341+ if ( ! showWorktrees && this . showWorktreesInSidebar ) {
4342+ setBoolean ( showWorktreesInSidebarKey , false )
4343+ this . showWorktreesInSidebar = false
4344+ this . lastSidebarWorktreeRefreshAt . clear ( )
4345+ }
41944346 this . updateResizableConstraints ( )
41954347 this . emitUpdate ( )
41964348 }
41974349
4350+ public _setShowWorktreesInSidebar ( showWorktreesInSidebar : boolean ) {
4351+ if ( this . showWorktreesInSidebar === showWorktreesInSidebar ) {
4352+ return
4353+ }
4354+
4355+ if ( showWorktreesInSidebar && ! this . showWorktrees ) {
4356+ return
4357+ }
4358+
4359+ setBoolean ( showWorktreesInSidebarKey , showWorktreesInSidebar )
4360+ this . showWorktreesInSidebar = showWorktreesInSidebar
4361+ this . lastSidebarWorktreeRefreshAt . clear ( )
4362+ this . emitUpdate ( )
4363+ }
4364+
41984365 public _setShowCompareTab ( showCompareTab : boolean ) {
41994366 if ( this . showCompareTab === showCompareTab ) {
42004367 return
0 commit comments