diff --git a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts index 01e2402dd..fe0f6a31a 100644 --- a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts +++ b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.html.ts @@ -21,7 +21,7 @@ export const REPOSITORY_STACKVIEW_TEMPLATE: string = ` {{r.name}} {{r.tags_count}} {{r.pull_count}} - + {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}} diff --git a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.spec.ts b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.spec.ts index 8cd205e33..de680f10d 100644 --- a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.spec.ts +++ b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; @@ -17,18 +17,15 @@ import { SystemInfoService, SystemInfoDefaultService } from '../service/system-i import { click } from '../utils'; -describe('RepositoryComponentStackview (inline template)', ()=> { - +describe('RepositoryComponentStackview (inline template)', () => { + let compRepo: RepositoryStackviewComponent; let fixtureRepo: ComponentFixture; let repositoryService: RepositoryService; - let spyRepos: jasmine.Spy; - - let compTag: TagComponent; - let fixtureTag: ComponentFixture; let tagService: TagService; let systemInfoService: SystemInfoService; + let spyRepos: jasmine.Spy; let spyTags: jasmine.Spy; let spySystemInfo: jasmine.Spy; @@ -44,27 +41,26 @@ describe('RepositoryComponentStackview (inline template)', ()=> { "harbor_version": "v1.1.1-rc1-160-g565110d" }; - let mockRepoData: Repository[] = [ { - "id": 1, - "name": "library/busybox", - "project_id": 1, - "description": "", - "pull_count": 0, - "star_count": 0, - "tags_count": 1 + "id": 1, + "name": "library/busybox", + "project_id": 1, + "description": "", + "pull_count": 0, + "star_count": 0, + "tags_count": 1 }, { - "id": 2, - "name": "library/nginx", - "project_id": 1, - "description": "", - "pull_count": 0, - "star_count": 0, - "tags_count": 1 + "id": 2, + "name": "library/nginx", + "project_id": 1, + "description": "", + "pull_count": 0, + "star_count": 0, + "tags_count": 1 } - ]; + ]; let mockTagData: Tag[] = [ { @@ -80,10 +76,12 @@ describe('RepositoryComponentStackview (inline template)', ()=> { ]; let config: IServiceConfig = { - repositoryBaseEndpoint: '/api/repository/testing' + repositoryBaseEndpoint: '/api/repository/testing', + systemInfoEndpoint: '/api/systeminfo/testing', + targetBaseEndpoint: '/api/tag/testing' }; - beforeEach(async(()=>{ + beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ SharedModule @@ -96,7 +94,7 @@ describe('RepositoryComponentStackview (inline template)', ()=> { ], providers: [ ErrorHandler, - { provide: SERVICE_CONFIG, useValue : config }, + { provide: SERVICE_CONFIG, useValue: config }, { provide: RepositoryService, useClass: RepositoryDefaultService }, { provide: TagService, useClass: TagDefaultService }, { provide: SystemInfoService, useClass: SystemInfoDefaultService } @@ -104,69 +102,74 @@ describe('RepositoryComponentStackview (inline template)', ()=> { }); })); - beforeEach(()=>{ + beforeEach(() => { fixtureRepo = TestBed.createComponent(RepositoryStackviewComponent); compRepo = fixtureRepo.componentInstance; compRepo.projectId = 1; compRepo.hasProjectAdminRole = true; repositoryService = fixtureRepo.debugElement.injector.get(RepositoryService); + systemInfoService = fixtureRepo.debugElement.injector.get(SystemInfoService); spyRepos = spyOn(repositoryService, 'getRepositories').and.returnValues(Promise.resolve(mockRepoData)); - fixtureRepo.detectChanges(); - }); - - beforeEach(()=>{ - fixtureTag = TestBed.createComponent(TagComponent); - compTag = fixtureTag.componentInstance; - compTag.projectId = compRepo.projectId; - compTag.repoName = 'library/busybox'; - compTag.hasProjectAdminRole = true; - compTag.hasSignedIn = true; - tagService = fixtureTag.debugElement.injector.get(TagService); - systemInfoService = fixtureTag.debugElement.injector.get(SystemInfoService); - spyTags = spyOn(tagService, 'getTags').and.returnValues(Promise.resolve(mockTagData)); spySystemInfo = spyOn(systemInfoService, 'getSystemInfo').and.returnValues(Promise.resolve(mockSystemInfo)); - fixtureTag.detectChanges(); + fixtureRepo.detectChanges(); }); - it('should load and render data', async(()=>{ + it('should create', () => { + expect(compRepo).toBeTruthy(); + }); + + it('should load and render data', async(() => { fixtureRepo.detectChanges(); - fixtureRepo.whenStable().then(()=>{ + + fixtureRepo.whenStable().then(() => { fixtureRepo.detectChanges(); + let deRepo: DebugElement = fixtureRepo.debugElement.query(By.css('datagrid-cell')); - fixtureRepo.detectChanges(); expect(deRepo).toBeTruthy(); let elRepo: HTMLElement = deRepo.nativeElement; - fixtureRepo.detectChanges(); expect(elRepo).toBeTruthy(); - fixtureRepo.detectChanges(); expect(elRepo.textContent).toEqual('library/busybox'); - click(deRepo); - fixtureTag.detectChanges(); - let deTag: DebugElement = fixtureTag.debugElement.query(By.css('datagrid-cell')); - expect(deTag).toBeTruthy(); - let elTag: HTMLElement = deTag.nativeElement; - expect(elTag).toBeTruthy(); - expect(elTag.textContent).toEqual('1.12.5'); }); })); - it('should filter data by keyword', async(()=>{ + it('should filter data by keyword', async(() => { fixtureRepo.detectChanges(); - fixtureRepo.whenStable().then(()=>{ + + fixtureRepo.whenStable().then(() => { fixtureRepo.detectChanges(); + compRepo.doSearchRepoNames('nginx'); fixtureRepo.detectChanges(); let de: DebugElement[] = fixtureRepo.debugElement.queryAll(By.css('datagrid-cell')); - fixtureRepo.detectChanges(); expect(de).toBeTruthy(); expect(de.length).toEqual(1); let el: HTMLElement = de[0].nativeElement; - fixtureRepo.detectChanges(); expect(el).toBeTruthy(); expect(el.textContent).toEqual('library/nginx'); }); })); + it('should display embedded tag view when click >', async(() => { + fixtureRepo.detectChanges(); + + fixtureRepo.whenStable().then(() => { + fixtureRepo.detectChanges(); + + let el: HTMLElement = fixtureRepo.nativeElement.querySelector('.datagrid-expandable-caret'); + expect(el).toBeTruthy(); + let button: HTMLButtonElement = el.querySelector('button'); + expect(button).toBeTruthy(); + click(button); + + fixtureRepo.detectChanges(); + let el2: HTMLElement = fixtureRepo.nativeElement.querySelector('.datagrid-row-detail'); + expect(el2).toBeTruthy(); + let el3: Element = el2.querySelector(".datagrid-cell"); + expect(el3).toBeTruthy(); + expect(el3.textContent).toEqual('1.11.5'); + }); + })); + }); \ No newline at end of file diff --git a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts index 41d848753..c6d1a5ce3 100644 --- a/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts +++ b/src/ui_ng/lib/src/repository-stackview/repository-stackview.component.ts @@ -5,9 +5,13 @@ import { Comparator } from 'clarity-angular'; import { REPOSITORY_STACKVIEW_TEMPLATE } from './repository-stackview.component.html'; import { REPOSITORY_STACKVIEW_STYLES } from './repository-stackview.component.css'; -import { Repository } from '../service/interface'; +import { + Repository, + SystemInfo, + SystemInfoService, + RepositoryService +} from '../service/index'; import { ErrorHandler } from '../error-handler/error-handler'; -import { RepositoryService } from '../service/repository.service'; import { toPromise, CustomComparator } from '../utils'; @@ -21,7 +25,7 @@ import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'hbr-repository-stackview', template: REPOSITORY_STACKVIEW_TEMPLATE, - styles: [ REPOSITORY_STACKVIEW_STYLES ], + styles: [REPOSITORY_STACKVIEW_STYLES], changeDetection: ChangeDetectionStrategy.OnPush }) export class RepositoryStackviewComponent implements OnInit { @@ -33,20 +37,30 @@ export class RepositoryStackviewComponent implements OnInit { lastFilteredRepoName: string; repositories: Repository[]; + systemInfo: SystemInfo; @ViewChild('confirmationDialog') confirmationDialog: ConfirmationDialogComponent; pullCountComparator: Comparator = new CustomComparator('pull_count', 'number'); - + tagsCountComparator: Comparator = new CustomComparator('tags_count', 'number'); constructor( private errorHandler: ErrorHandler, private translateService: TranslateService, private repositoryService: RepositoryService, - private ref: ChangeDetectorRef){} - + private systemInfoService: SystemInfoService, + private ref: ChangeDetectorRef) { } + + public get registryUrl(): string { + return this.systemInfo ? this.systemInfo.registry_url : ""; + } + + public get withNotary(): boolean { + return this.systemInfo ? this.systemInfo.with_notary : false; + } + confirmDeletion(message: ConfirmationAcknowledgement) { if (message && message.source === ConfirmationTargets.REPOSITORY && @@ -55,19 +69,24 @@ export class RepositoryStackviewComponent implements OnInit { toPromise(this.repositoryService .deleteRepository(repoName)) .then( - response => { - this.refresh(); - this.translateService.get('REPOSITORY.DELETED_REPO_SUCCESS') - .subscribe(res=>this.errorHandler.info(res)); + response => { + this.refresh(); + this.translateService.get('REPOSITORY.DELETED_REPO_SUCCESS') + .subscribe(res => this.errorHandler.info(res)); }).catch(error => this.errorHandler.error(error)); } } ngOnInit(): void { - if(!this.projectId) { + if (!this.projectId) { this.errorHandler.error('Project ID cannot be unset.'); return; - } + } + //Get system info for tag views + toPromise(this.systemInfoService.getSystemInfo()) + .then(systemInfo => this.systemInfo = systemInfo) + .catch(error => this.errorHandler.error(error)); + this.lastFilteredRepoName = ''; this.retrieve(); } @@ -76,10 +95,10 @@ export class RepositoryStackviewComponent implements OnInit { toPromise(this.repositoryService .getRepositories(this.projectId, this.lastFilteredRepoName)) .then( - repos => this.repositories = repos, - error => this.errorHandler.error(error)); - let hnd = setInterval(()=>this.ref.markForCheck(), 100); - setTimeout(()=>clearInterval(hnd), 1000); + repos => this.repositories = repos, + error => this.errorHandler.error(error)); + let hnd = setInterval(() => this.ref.markForCheck(), 100); + setTimeout(() => clearInterval(hnd), 1000); } doSearchRepoNames(repoName: string) { diff --git a/src/ui_ng/lib/src/tag/tag.component.spec.ts b/src/ui_ng/lib/src/tag/tag.component.spec.ts index 8f7f7a052..ce5877a85 100644 --- a/src/ui_ng/lib/src/tag/tag.component.spec.ts +++ b/src/ui_ng/lib/src/tag/tag.component.spec.ts @@ -8,33 +8,16 @@ import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation import { TagComponent } from './tag.component'; import { ErrorHandler } from '../error-handler/error-handler'; -import { SystemInfo, Tag } from '../service/interface'; +import { Tag } from '../service/interface'; import { SERVICE_CONFIG, IServiceConfig } from '../service.config'; import { TagService, TagDefaultService } from '../service/tag.service'; -import { SystemInfoService, SystemInfoDefaultService } from '../service/system-info.service'; describe('TagComponent (inline template)', ()=> { let comp: TagComponent; let fixture: ComponentFixture; let tagService: TagService; - let systemInfoService: SystemInfoService; let spy: jasmine.Spy; - let spySystemInfo: jasmine.Spy; - - - let mockSystemInfo: SystemInfo = { - "with_notary": true, - "with_admiral": false, - "admiral_endpoint": "NA", - "auth_mode": "db_auth", - "registry_url": "10.112.122.56", - "project_creation_restriction": "everyone", - "self_registration": true, - "has_ca_root": false, - "harbor_version": "v1.1.1-rc1-160-g565110d" - }; - let mockTags: Tag[] = [ { "digest": "sha256:e5c82328a509aeb7c18c1d7fb36633dc638fcf433f651bdcda59c1cc04d3ee55", @@ -64,8 +47,7 @@ describe('TagComponent (inline template)', ()=> { providers: [ ErrorHandler, { provide: SERVICE_CONFIG, useValue: config }, - { provide: TagService, useClass: TagDefaultService }, - { provide: SystemInfoService, useClass: SystemInfoDefaultService } + { provide: TagService, useClass: TagDefaultService } ] }); })); @@ -78,11 +60,11 @@ describe('TagComponent (inline template)', ()=> { comp.repoName = 'library/nginx'; comp.hasProjectAdminRole = true; comp.hasSignedIn = true; + comp.registryUrl = 'http://registry.testing.com'; + comp.withNotary = false; tagService = fixture.debugElement.injector.get(TagService); - systemInfoService = fixture.debugElement.injector.get(SystemInfoService); spy = spyOn(tagService, 'getTags').and.returnValues(Promise.resolve(mockTags)); - spySystemInfo = spyOn(systemInfoService, 'getSystemInfo').and.returnValues(Promise.resolve(mockSystemInfo)); fixture.detectChanges(); }); diff --git a/src/ui_ng/lib/src/tag/tag.component.ts b/src/ui_ng/lib/src/tag/tag.component.ts index 50e736a5f..361fcfef4 100644 --- a/src/ui_ng/lib/src/tag/tag.component.ts +++ b/src/ui_ng/lib/src/tag/tag.component.ts @@ -14,7 +14,6 @@ import { Component, OnInit, ViewChild, Input, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; import { TagService } from '../service/tag.service'; -import { SystemInfoService } from '../service/system-info.service'; import { ErrorHandler } from '../error-handler/error-handler'; import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../shared/shared.const'; @@ -23,7 +22,7 @@ import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation import { ConfirmationMessage } from '../confirmation-dialog/confirmation-message'; import { ConfirmationAcknowledgement } from '../confirmation-dialog/confirmation-state-message'; -import { SystemInfo, Tag } from '../service/interface'; +import { Tag } from '../service/interface'; import { TAG_TEMPLATE } from './tag.component.html'; import { TAG_STYLE } from './tag.component.css'; @@ -37,24 +36,24 @@ import { State, Comparator } from 'clarity-angular'; @Component({ selector: 'hbr-tag', template: TAG_TEMPLATE, - styles: [ TAG_STYLE ], + styles: [TAG_STYLE], changeDetection: ChangeDetectionStrategy.OnPush }) export class TagComponent implements OnInit { @Input() projectId: number; @Input() repoName: string; - @Input() isEmbedded: boolean; + @Input() isEmbedded: boolean; @Input() hasSignedIn: boolean; @Input() hasProjectAdminRole: boolean; + @Input() registryUrl: string; + @Input() withNotary: boolean; @Output() refreshRepo = new EventEmitter(); tags: Tag[]; - registryUrl: string; - withNotary: boolean; showTagManifestOpened: boolean; manifestInfoTitle: string; @@ -71,10 +70,9 @@ export class TagComponent implements OnInit { constructor( private errorHandler: ErrorHandler, - private systemInfoService: SystemInfoService, private tagService: TagService, private translateService: TranslateService, - private ref: ChangeDetectorRef){} + private ref: ChangeDetectorRef) { } confirmDeletion(message: ConfirmationAcknowledgement) { if (message && @@ -86,35 +84,28 @@ export class TagComponent implements OnInit { return; } else { toPromise(this.tagService - .deleteTag(this.repoName, tag.name)) - .then( - response => { + .deleteTag(this.repoName, tag.name)) + .then( + response => { this.retrieve(); this.translateService.get('REPOSITORY.DELETED_TAG_SUCCESS') - .subscribe(res=>this.errorHandler.info(res)); - }).catch(error => this.errorHandler.error(error)); + .subscribe(res => this.errorHandler.info(res)); + }).catch(error => this.errorHandler.error(error)); } } } } ngOnInit() { - if(!this.projectId) { + if (!this.projectId) { this.errorHandler.error('Project ID cannot be unset.'); return; } - if(!this.repoName) { + if (!this.repoName) { this.errorHandler.error('Repo name cannot be unset.'); return; } - toPromise(this.systemInfoService.getSystemInfo()) - .then(systemInfo=>{ - if(systemInfo) { - this.registryUrl = systemInfo.registry_url || ''; - this.withNotary = systemInfo.with_notary || false; - } - }, - error=> this.errorHandler.error(error)); + this.retrieve(); } @@ -122,20 +113,20 @@ export class TagComponent implements OnInit { this.tags = []; this.loading = true; toPromise(this.tagService - .getTags(this.repoName)) - .then(items => { - this.tags = items; - this.loading = false; - if(this.tags && this.tags.length === 0) { - this.refreshRepo.emit(true); - } - }) - .catch(error => { - this.errorHandler.error(error); - this.loading = false; - }); - let hnd = setInterval(()=>this.ref.markForCheck(), 100); - setTimeout(()=>clearInterval(hnd), 1000); + .getTags(this.repoName)) + .then(items => { + this.tags = items; + this.loading = false; + if (this.tags && this.tags.length === 0) { + this.refreshRepo.emit(true); + } + }) + .catch(error => { + this.errorHandler.error(error); + this.loading = false; + }); + let hnd = setInterval(() => this.ref.markForCheck(), 100); + setTimeout(() => clearInterval(hnd), 1000); } deleteTag(tag: Tag) { @@ -164,7 +155,7 @@ export class TagComponent implements OnInit { } showDigestId(tag: Tag) { - if(tag) { + if (tag) { this.manifestInfoTitle = 'REPOSITORY.COPY_DIGEST_ID'; this.digestId = tag.digest; this.showTagManifestOpened = true;