From 13b3233faf132ef7706ca8fb07618064adbc75a5 Mon Sep 17 00:00:00 2001 From: Shijun Sun <30999793+AllForNothing@users.noreply.github.com> Date: Thu, 15 Sep 2022 11:37:36 +0800 Subject: [PATCH] Refactor artifact-list-tab component (#17542) Signed-off-by: AllForNothing --- .../artifact-list-tab.component.html | 54 +------------ .../artifact-list-tab.component.spec.ts | 4 +- .../artifact-list-tab.component.ts | 77 ++----------------- .../copy-artifact.component.html | 25 ++++++ .../copy-artifact.component.scss | 0 .../copy-artifact.component.spec.ts | 57 ++++++++++++++ .../copy-artifact/copy-artifact.component.ts | 76 ++++++++++++++++++ .../copy-digest/copy-digest.component.html | 27 +++++++ .../copy-digest/copy-digest.component.scss | 0 .../copy-digest/copy-digest.component.spec.ts | 32 ++++++++ .../copy-digest/copy-digest.component.ts | 33 ++++++++ .../repository/artifact/artifact.module.ts | 4 + 12 files changed, 266 insertions(+), 123 deletions(-) create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.html create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.scss create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.spec.ts create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.ts create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.html create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.scss create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.spec.ts create mode 100644 src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.ts diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html index 9705eccbd..279d3a7de 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html @@ -3,58 +3,8 @@ #confirmationDialog (confirmAction)="confirmDeletion($event)"> - - - - - - - - - - + +
{ beforeEach(async () => { await TestBed.configureTestingModule({ imports: [SharedTestingModule], - schemas: [CUSTOM_ELEMENTS_SCHEMA], + schemas: [NO_ERRORS_SCHEMA], declarations: [ArtifactListTabComponent], providers: [ { diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts index 9d4e9895e..f280126aa 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts @@ -95,6 +95,8 @@ import { ArtifactListPageService } from '../../artifact-list-page.service'; import { ACCESSORY_PAGE_SIZE } from './sub-accessories/sub-accessories.component'; import { Accessory } from 'ng-swagger-gen/models/accessory'; import { Tag } from '../../../../../../../../../ng-swagger-gen/models/tag'; +import { CopyArtifactComponent } from './copy-artifact/copy-artifact.component'; +import { CopyDigestComponent } from './copy-digest/copy-digest.component'; export interface LabelState { iconsShow: boolean; @@ -120,17 +122,10 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { registryUrl: string; artifactList: ArtifactFront[] = []; availableTime = AVAILABLE_TIME; - showTagManifestOpened: boolean; - retagDialogOpened: boolean; - manifestInfoTitle: string; - digestId: string; - staticBackdrop = true; - closable = false; lastFilteredTagName: string; inprogress: boolean; openLabelFilterPanel: boolean; openLabelFilterPiece: boolean; - retagSrcImage: string; showlabel: boolean; pullComparator: Comparator = new CustomComparator( @@ -143,7 +138,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { ); loading = true; - copyFailed = false; selectedRow: Artifact[] = []; labelListOpen = false; selectedTag: Artifact[]; @@ -164,10 +158,10 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { @ViewChild('confirmationDialog') confirmationDialog: ConfirmationDialogComponent; - @ViewChild('imageNameInput') - imageNameInput: ImageNameInputComponent; - - @ViewChild('digestTarget') textInput: ElementRef; + @ViewChild(CopyArtifactComponent) + copyArtifactComponent: CopyArtifactComponent; + @ViewChild(CopyDigestComponent) + copyDigestComponent: CopyDigestComponent; pageSize: number = getPageSizeFromLocalStorage( PageSizeMapKeys.ARTIFACT_LIST_TAB_COMPONENT ); @@ -846,47 +840,10 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { retag() { if (this.selectedRow && this.selectedRow.length && !this.depth) { - this.retagDialogOpened = true; - this.imageNameInput.imageNameForm.reset({ - repoName: this.repoName, - projectName: null, - }); - this.imageNameInput.notExist = false; - this.retagSrcImage = - this.repoName + ':' + this.selectedRow[0].digest; + this.copyArtifactComponent.retag(this.selectedRow[0].digest); } } - onRetag() { - let params: NewArtifactService.CopyArtifactParams = { - projectName: this.imageNameInput.projectName.value, - repositoryName: dbEncodeURIComponent( - this.imageNameInput.repoName.value - ), - from: `${this.projectName}/${this.repoName}@${this.selectedRow[0].digest}`, - }; - this.newArtifactService - .CopyArtifact(params) - .pipe( - finalize(() => { - this.imageNameInput.form.reset(); - this.retagDialogOpened = false; - }) - ) - .subscribe( - response => { - this.translateService - .get('RETAG.MSG_SUCCESS') - .subscribe((res: string) => { - this.errorHandlerService.info(res); - }); - }, - error => { - this.errorHandlerService.error(error); - } - ); - } - deleteArtifact() { if (this.selectedRow && this.selectedRow.length && !this.depth) { let artifactNames: string[] = []; @@ -1059,10 +1016,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { showDigestId() { if (this.selectedRow && this.selectedRow.length === 1 && !this.depth) { - this.manifestInfoTitle = 'REPOSITORY.COPY_DIGEST_ID'; - this.digestId = this.selectedRow[0].digest; - this.showTagManifestOpened = true; - this.copyFailed = false; + this.copyDigestComponent.showDigestId(this.selectedRow[0].digest); } } @@ -1080,21 +1034,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { } } - onSuccess($event: any): void { - this.copyFailed = false; - // Directly close dialog - this.showTagManifestOpened = false; - } - - onError($event: any): void { - // Show error - this.copyFailed = true; - // Select all text - if (this.textInput) { - this.textInput.nativeElement.select(); - } - } - // Get vulnerability scanning status scanStatus(artifact: Artifact): string { if (artifact) { diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.html new file mode 100644 index 000000000..635561143 --- /dev/null +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.html @@ -0,0 +1,25 @@ + + + + + diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.scss b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.spec.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.spec.ts new file mode 100644 index 000000000..aaf8c2e06 --- /dev/null +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.spec.ts @@ -0,0 +1,57 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CopyArtifactComponent } from './copy-artifact.component'; +import { SharedTestingModule } from '../../../../../../../../shared/shared.module'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ArtifactService } from 'ng-swagger-gen/services/artifact.service'; +import { of } from 'rxjs'; + +describe('CopyArtifactComponent', () => { + let component: CopyArtifactComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + schemas: [NO_ERRORS_SCHEMA], + declarations: [CopyArtifactComponent], + imports: [SharedTestingModule, RouterTestingModule], + }).compileComponents(); + + fixture = TestBed.createComponent(CopyArtifactComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should open modal', async () => { + component.retag(`sha256@test`); + fixture.detectChanges(); + await fixture.whenStable(); + const modal = fixture.nativeElement.querySelector(`clr-modal`); + expect(modal).toBeTruthy(); + }); + it('should call retag API', async () => { + const artifactService: ArtifactService = + TestBed.inject(ArtifactService); + const spy: jasmine.Spy = spyOn( + artifactService, + `CopyArtifact` + ).and.returnValue(of(null)); + component.retagDialogOpened = true; + component.imageNameInput.imageNameForm.reset({ + repoName: `test`, + projectName: `test`, + }); + fixture.detectChanges(); + await fixture.whenStable(); + const btn: HTMLButtonElement = + fixture.nativeElement.querySelector(`.btn-primary`); + btn.click(); + fixture.detectChanges(); + expect(spy.calls.count()).toEqual(1); + }); +}); diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.ts new file mode 100644 index 000000000..71bde1191 --- /dev/null +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component.ts @@ -0,0 +1,76 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { dbEncodeURIComponent } from '../../../../../../../../shared/units/utils'; +import { finalize } from 'rxjs/operators'; +import { ArtifactService } from 'ng-swagger-gen/services/artifact.service'; +import { ImageNameInputComponent } from '../../../../../../../../shared/components/image-name-input/image-name-input.component'; +import { Project } from '../../../../../../project'; +import { ActivatedRoute } from '@angular/router'; +import { ErrorHandler } from '../../../../../../../../shared/units/error-handler'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'app-copy-artifact', + templateUrl: './copy-artifact.component.html', + styleUrls: ['./copy-artifact.component.scss'], +}) +export class CopyArtifactComponent implements OnInit { + retagDialogOpened: boolean = false; + projectName: string; + repoName: string; + @ViewChild('imageNameInput') + imageNameInput: ImageNameInputComponent; + digest: string; + constructor( + private activatedRoute: ActivatedRoute, + private artifactService: ArtifactService, + private errorHandlerService: ErrorHandler, + private translateService: TranslateService + ) {} + + ngOnInit(): void { + const resolverData = this.activatedRoute.snapshot?.parent?.parent?.data; + if (resolverData) { + this.projectName = (resolverData['projectResolver']).name; + } + this.repoName = this.activatedRoute.snapshot?.parent?.params['repo']; + } + + onRetag() { + let params: ArtifactService.CopyArtifactParams = { + projectName: this.imageNameInput.projectName.value, + repositoryName: dbEncodeURIComponent( + this.imageNameInput.repoName.value + ), + from: `${this.projectName}/${this.repoName}@${this.digest}`, + }; + this.artifactService + .CopyArtifact(params) + .pipe( + finalize(() => { + this.imageNameInput.form.reset(); + this.retagDialogOpened = false; + }) + ) + .subscribe({ + next: response => { + this.translateService + .get('RETAG.MSG_SUCCESS') + .subscribe((res: string) => { + this.errorHandlerService.info(res); + }); + }, + error: error => { + this.errorHandlerService.error(error); + }, + }); + } + retag(digest: string) { + this.retagDialogOpened = true; + this.imageNameInput.imageNameForm.reset({ + repoName: this.repoName, + projectName: null, + }); + this.digest = digest; + this.imageNameInput.notExist = false; + } +} diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.html new file mode 100644 index 000000000..1e52ef633 --- /dev/null +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.html @@ -0,0 +1,27 @@ + + + + + diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.scss b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.spec.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.spec.ts new file mode 100644 index 000000000..b1ec245f8 --- /dev/null +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.spec.ts @@ -0,0 +1,32 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { CopyDigestComponent } from './copy-digest.component'; +import { SharedTestingModule } from '../../../../../../../../shared/shared.module'; + +describe('CopyDigestComponent', () => { + let component: CopyDigestComponent; + let fixture: ComponentFixture; + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CopyDigestComponent], + imports: [SharedTestingModule], + }).compileComponents(); + + fixture = TestBed.createComponent(CopyDigestComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show right digest', async () => { + const digest: string = 'sha256@test'; + component.showDigestId(digest); + fixture.detectChanges(); + await fixture.whenStable(); + const textArea: HTMLTextAreaElement = + fixture.nativeElement.querySelector(`textarea`); + expect(textArea.textContent).toEqual(digest); + }); +}); diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.ts new file mode 100644 index 000000000..089ce6843 --- /dev/null +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component.ts @@ -0,0 +1,33 @@ +import { Component, ElementRef, ViewChild } from '@angular/core'; + +@Component({ + selector: 'app-copy-digest', + templateUrl: './copy-digest.component.html', + styleUrls: ['./copy-digest.component.scss'], +}) +export class CopyDigestComponent { + showTagManifestOpened: boolean = false; + digestId: string; + @ViewChild('digestTarget') textInput: ElementRef; + copyFailed: boolean = false; + constructor() {} + onSuccess($event: any): void { + this.copyFailed = false; + // Directly close dialog + this.showTagManifestOpened = false; + } + + onError($event: any): void { + // Show error + this.copyFailed = true; + // Select all text + if (this.textInput) { + this.textInput.nativeElement.select(); + } + } + showDigestId(digest: string) { + this.digestId = digest; + this.showTagManifestOpened = true; + this.copyFailed = false; + } +} diff --git a/src/portal/src/app/base/project/repository/artifact/artifact.module.ts b/src/portal/src/app/base/project/repository/artifact/artifact.module.ts index 7e5d65d08..c8e54a770 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact.module.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact.module.ts @@ -21,6 +21,8 @@ import { HistogramChartComponent } from './vulnerability-scanning/histogram-char import { ArtifactInfoComponent } from './artifact-list-page/artifact-list/artifact-info/artifact-info.component'; import { SubAccessoriesComponent } from './artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component'; import { ArtifactListPageService } from './artifact-list-page/artifact-list-page.service'; +import { CopyArtifactComponent } from './artifact-list-page/artifact-list/artifact-list-tab/copy-artifact/copy-artifact.component'; +import { CopyDigestComponent } from './artifact-list-page/artifact-list/artifact-list-tab/copy-digest/copy-digest.component'; const routes: Routes = [ { @@ -82,6 +84,8 @@ const routes: Routes = [ HistogramChartComponent, ArtifactInfoComponent, SubAccessoriesComponent, + CopyArtifactComponent, + CopyDigestComponent, ], imports: [RouterModule.forChild(routes), SharedModule], providers: [