import { Component , OnDestroy } from '@angular/core' ; import { DropDownElement } from 'app/shared/models/drop-down-element' ; import { DeploymentCenterStateManager } from 'app/site/deployment-center/deployment-center-setup/wizard-logic/deployment-center-state-manager' ; import { CacheService } from 'app/shared/services/cache.service' ; import { Constants , LogCategories , DeploymentCenterConstants } from 'app/shared/models/constants' ; import { LogService } from 'app/shared/services/log.service' ; import { Subject } from 'rxjs/Subject' ; import { RequiredValidator } from '../../../../../shared/validators/requiredValidator' ; import { TranslateService } from '@ngx-translate/core' ; import { Observable } from 'rxjs/Observable' ; import { forkJoin } from 'rxjs/observable/forkJoin' ; @ Component ( { selector : 'app-configure-bitbucket' , templateUrl : './configure-bitbucket.component.html' , styleUrls : [ './configure-bitbucket.component.scss' , '../step-configure.component.scss' , '../../deployment-center-setup.component.scss' ] , } ) export class ConfigureBitbucketComponent implements OnDestroy { public OrgList : DropDownElement < string > [ ] = [ ] ; public RepoList : DropDownElement < string > [ ] = [ ] ; public BranchList : DropDownElement < string > [ ] = [ ] ; public bitbucketInfoboxMessageLink = DeploymentCenterConstants . permissionsInfoLink ; private _orgRepoMap : { [ key ] : DropDownElement < string > [ ] ; } ; private _reposStream$ = new Subject < string > ( ) ; private _ngUnsubscribe$ = new Subject ( ) ; private _repoUrlToNameMap : { [ key ] : string ; } = { } ; selectedOrg = null ; selectedRepo = null ; selectedBranch = null ; public reposLoading = false ; public branchesLoading = false ; public orgsLoading = false ; constructor ( public wizard , private _cacheService , private _logService , private _translateService ) { this . _reposStream$ . takeUntil ( this . _ngUnsubscribe$ ) . subscribe ( r => { this . fetchBranches ( r ) ; } ) ; this . updateFormValidation ( ) ; this . wizard . updateSourceProviderConfig$ . takeUntil ( this . _ngUnsubscribe$ ) . subscribe ( r => { this . fetchOrgsAndRepos ( ) ; } ) ; this . wizard . bitBucketToken$ . takeUntil ( this . _ngUnsubscribe$ ) . distinctUntilChanged ( ) . subscribe ( token => { this . fetchOrgsAndRepos ( ) ; } ) ; } updateFormValidation ( ) { const required = new RequiredValidator ( this . _translateService , false ) ; this . wizard . sourceSettings . get ( 'repoUrl' ) . setValidators ( required . validate . bind ( required ) ) ; this . wizard . sourceSettings . get ( 'branch' ) . setValidators ( required . validate . bind ( required ) ) ; this . wizard . sourceSettings . get ( 'repoUrl' ) . updateValueAndValidity ( ) ; this . wizard . sourceSettings . get ( 'branch' ) . updateValueAndValidity ( ) ; } fetchOrgsAndRepos ( ) { this . OrgList = [ ] ; this . orgsLoading = true ; const repos = [ ] ; const repoCalls = this . _cacheService . post ( Constants . serviceHost + `api/bitbucket/passthrough?repo=` , true , null , { url : `${ DeploymentCenterConstants . bitbucketApiUrl }/repositories?pagelen=100&role=contributor` , bitBucketToken : this . wizard . bitBucketToken$ . getValue ( ) , } ) . first ( ) . expand ( value => { const page = value . json ( ) ; page . values . forEach ( repo => { repos . push ( repo ) ; } ) ; if ( ! page . next ) { return Observable . empty ( ) ; } else { return this . _cacheService . post ( Constants . serviceHost + `api/bitbucket/passthrough?repo=` , true , null , { url : page . next , bitBucketToken : this . wizard . bitBucketToken$ . getValue ( ) , } ) ; } } ) ; this . _repoUrlToNameMap = { } ; forkJoin ( repoCalls ) . subscribe ( v => { this . _orgRepoMap = repos . reduce ( ( acc , repo ) => { const repoNamePieces = repo . full_name . split ( '/' ) ; const repoUrl = `${ DeploymentCenterConstants . bitbucketUrl }/${ repo . full_name }` ; this . _repoUrlToNameMap [ repoUrl ] = repo . full_name ; const repoVal = { displayLabel : repo . name , value : repoUrl , } ; if ( acc [ repoNamePieces [ 0 ] ] ) { acc [ repoNamePieces [ 0 ] ] . push ( repoVal ) ; } else { acc [ repoNamePieces [ 0 ] ] = [ repoVal ] ; } return acc ; } , { } ) ; const orgNames = new Set ( Object . keys ( this . _orgRepoMap ) ) ; this . OrgList = [ ... orgNames ] . map ( x => ( { displayLabel : x , value : x , } ) ) ; this . orgsLoading = false ; } , err => { this . _logService . error ( LogCategories . cicd , '/fetch-bitbucket-branches' , err ) ; this . orgsLoading = false ; } ) ; } fetchRepos ( team ) { this . RepoList = this . _orgRepoMap [ team ] ; } fetchBranches ( repo ) { this . branchesLoading = true ; this . BranchList = [ ] ; const newBranchList = [ ] ; Observable . forkJoin ( this . _cacheService . post ( Constants . serviceHost + `api/bitbucket/passthrough?branch=${ repo }` , true , null , { url : `${ DeploymentCenterConstants . bitbucketApiUrl }/repositories/${ repo }/refs/branches?pagelen=100` , bitBucketToken : this . wizard . bitBucketToken$ . getValue ( ) , } ) . expand ( value => { const page = value . json ( ) ; page . values . forEach ( branch => { newBranchList . push ( { displayLabel : branch . name , value : branch . name , } ) ; } ) ; if ( ! page . next ) { return Observable . empty ( ) ; } else { return this . _cacheService . post ( Constants . serviceHost + `api/bitbucket/passthrough?repo=` , true , null , { url : page . next , bitBucketToken : this . wizard . bitBucketToken$ . getValue ( ) , } ) ; } } ) ) . subscribe ( r => { this . branchesLoading = false ; this . BranchList = newBranchList ; } , err => { this . branchesLoading = false ; this . _logService . error ( LogCategories . cicd , '/fetch-bitbucket-branches' , err ) ; } ) ; } RepoChanged ( repo ) { this . _reposStream$ . next ( this . _repoUrlToNameMap [ repo . value ] ) ; this . selectedBranch = null ; } OrgChanged ( org ) { this . fetchRepos ( org . value ) ; this . selectedRepo = null ; this . selectedBranch = null ; } ngOnDestroy ( ) { this . _ngUnsubscribe$ . next ( ) ; } }