@@ -10,7 +10,7 @@ import { append, $ } from '../../../../base/browser/dom.js';
10
10
import { IListVirtualDelegate , IIdentityProvider } from '../../../../base/browser/ui/list/list.js' ;
11
11
import { IAsyncDataSource , ITreeEvent , ITreeContextMenuEvent } from '../../../../base/browser/ui/tree/tree.js' ;
12
12
import { WorkbenchCompressibleAsyncDataTree } from '../../../../platform/list/browser/listService.js' ;
13
- import { ISCMRepository , ISCMViewService } from '../common/scm.js' ;
13
+ import { ISCMRepository , ISCMService , ISCMViewService } from '../common/scm.js' ;
14
14
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js' ;
15
15
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js' ;
16
16
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js' ;
@@ -27,7 +27,7 @@ import { Iterable } from '../../../../base/common/iterator.js';
27
27
import { MenuId } from '../../../../platform/actions/common/actions.js' ;
28
28
import { IHoverService } from '../../../../platform/hover/browser/hover.js' ;
29
29
import { observableConfigValue } from '../../../../platform/observable/common/platformObservableUtils.js' ;
30
- import { autorun , IObservable , observableSignalFromEvent } from '../../../../base/common/observable.js' ;
30
+ import { autorun , IObservable , observableFromEvent , observableSignalFromEvent } from '../../../../base/common/observable.js' ;
31
31
import { Sequencer } from '../../../../base/common/async.js' ;
32
32
33
33
class ListDelegate implements IListVirtualDelegate < ISCMRepository > {
@@ -57,20 +57,6 @@ class RepositoryTreeDataSource extends Disposable implements IAsyncDataSource<IS
57
57
return repositories ;
58
58
}
59
59
60
- getParent ( element : ISCMViewService | ISCMRepository ) : ISCMViewService | ISCMRepository {
61
- if ( ! isSCMRepository ( element ) ) {
62
- throw new Error ( 'Unexpected call to getParent' ) ;
63
- }
64
-
65
- const repository = this . scmViewService . repositories
66
- . find ( r => r . provider . id === element . provider . parentId ) ;
67
- if ( ! repository ) {
68
- throw new Error ( 'Invalid element passed to getParent' ) ;
69
- }
70
-
71
- return repository ;
72
- }
73
-
74
60
hasChildren ( inputOrElement : ISCMViewService | ISCMRepository ) : boolean {
75
61
const parentId = isSCMRepository ( inputOrElement )
76
62
? inputOrElement . provider . id
@@ -103,6 +89,7 @@ export class SCMRepositoriesViewPane extends ViewPane {
103
89
104
90
constructor (
105
91
options : IViewPaneOptions ,
92
+ @ISCMService private readonly scmService : ISCMService ,
106
93
@ISCMViewService private readonly scmViewService : ISCMViewService ,
107
94
@IKeybindingService keybindingService : IKeybindingService ,
108
95
@IContextMenuService contextMenuService : IContextMenuService ,
@@ -150,13 +137,29 @@ export class SCMRepositoriesViewPane extends ViewPane {
150
137
this . updateBodySize ( this . tree . contentHeight , visibleCount ) ;
151
138
} ) ) ;
152
139
153
- // Update tree
154
- const onDidChangeRepositoriesSignal = observableSignalFromEvent (
155
- this , this . scmViewService . onDidChangeRepositories ) ;
140
+ // Update tree (add/remove repositories)
141
+ const addedRepositoryObs = observableFromEvent (
142
+ this , this . scmService . onDidAddRepository , e => e ) ;
143
+
144
+ const removedRepositoryObs = observableFromEvent (
145
+ this , this . scmService . onDidRemoveRepository , e => e ) ;
156
146
157
147
this . visibilityDisposables . add ( autorun ( async reader => {
158
- onDidChangeRepositoriesSignal . read ( reader ) ;
159
- await this . treeOperationSequencer . queue ( ( ) => this . updateChildren ( ) ) ;
148
+ const addedRepository = addedRepositoryObs . read ( reader ) ;
149
+ const removedRepository = removedRepositoryObs . read ( reader ) ;
150
+
151
+ if ( addedRepository === undefined && removedRepository === undefined ) {
152
+ await this . updateChildren ( ) ;
153
+ return ;
154
+ }
155
+
156
+ if ( addedRepository ) {
157
+ await this . updateRepository ( addedRepository ) ;
158
+ }
159
+
160
+ if ( removedRepository ) {
161
+ await this . updateRepository ( removedRepository ) ;
162
+ }
160
163
} ) ) ;
161
164
162
165
// Update tree selection
@@ -203,6 +206,12 @@ export class SCMRepositoriesViewPane extends ViewPane {
203
206
{
204
207
identityProvider : this . treeIdentityProvider ,
205
208
horizontalScrolling : false ,
209
+ collapseByDefault : ( e : unknown ) => {
210
+ if ( isSCMRepository ( e ) && e . provider . parentId === undefined ) {
211
+ return false ;
212
+ }
213
+ return true ;
214
+ } ,
206
215
compressionEnabled : compressionEnabled . get ( ) ,
207
216
overrideStyles : this . getLocationBasedColors ( ) . listOverrideStyles ,
208
217
expandOnDoubleClick : false ,
@@ -267,11 +276,43 @@ export class SCMRepositoriesViewPane extends ViewPane {
267
276
268
277
private onTreeContentHeightChange ( height : number ) : void {
269
278
this . updateBodySize ( height ) ;
279
+
280
+ // Refresh the selection
281
+ this . treeOperationSequencer . queue ( ( ) => this . updateTreeSelection ( ) ) ;
270
282
}
271
283
272
- private async updateChildren ( ) : Promise < void > {
273
- await this . tree . updateChildren ( ) ;
274
- this . updateBodySize ( this . tree . contentHeight ) ;
284
+ private async updateChildren ( element ?: ISCMRepository ) : Promise < void > {
285
+ await this . treeOperationSequencer . queue ( async ( ) => {
286
+ if ( element && this . tree . hasNode ( element ) ) {
287
+ await this . tree . updateChildren ( element , true ) ;
288
+ } else {
289
+ await this . tree . updateChildren ( undefined , true ) ;
290
+ }
291
+ } ) ;
292
+ }
293
+
294
+ private async expand ( element : ISCMRepository ) : Promise < void > {
295
+ await this . treeOperationSequencer . queue ( ( ) => this . tree . expand ( element , true ) ) ;
296
+ }
297
+
298
+ private async updateRepository ( repository : ISCMRepository ) : Promise < void > {
299
+ if ( repository . provider . parentId === undefined ) {
300
+ await this . updateChildren ( ) ;
301
+ return ;
302
+ }
303
+
304
+ await this . updateParentRepository ( repository ) ;
305
+ }
306
+
307
+ private async updateParentRepository ( repository : ISCMRepository ) : Promise < void > {
308
+ const parentRepository = this . scmViewService . repositories
309
+ . find ( r => r . provider . id === repository . provider . parentId ) ;
310
+ if ( ! parentRepository ) {
311
+ return ;
312
+ }
313
+
314
+ await this . updateChildren ( parentRepository ) ;
315
+ await this . expand ( parentRepository ) ;
275
316
}
276
317
277
318
private updateBodySize ( contentHeight : number , visibleCount ?: number ) : void {
@@ -307,15 +348,14 @@ export class SCMRepositoriesViewPane extends ViewPane {
307
348
}
308
349
}
309
350
310
- // Expand all selected items
311
- for ( const item of selection ) {
312
- await this . tree . expandTo ( item ) ;
313
- }
314
- this . tree . setSelection ( selection ) ;
351
+ const visibleSelection = selection
352
+ . filter ( s => this . tree . hasNode ( s ) ) ;
353
+
354
+ this . tree . setSelection ( visibleSelection ) ;
315
355
316
- if ( selection . length > 0 && ! this . tree . getFocus ( ) . includes ( selection [ 0 ] ) ) {
317
- this . tree . setAnchor ( selection [ 0 ] ) ;
318
- this . tree . setFocus ( [ selection [ 0 ] ] ) ;
356
+ if ( visibleSelection . length > 0 && ! this . tree . getFocus ( ) . includes ( visibleSelection [ 0 ] ) ) {
357
+ this . tree . setAnchor ( visibleSelection [ 0 ] ) ;
358
+ this . tree . setFocus ( [ visibleSelection [ 0 ] ] ) ;
319
359
}
320
360
}
321
361
0 commit comments