From cba4490a5ad4b3de4dac8c9dfc3cd6f875634dd6 Mon Sep 17 00:00:00 2001 From: Yogi_Wang Date: Tue, 24 Mar 2020 10:56:18 +0800 Subject: [PATCH] [Fixed] Fix bug for 2.0 and add case for trivy Signed-off-by: Yogi_Wang 1.add case for trivy 2.vunerbility refresh bug 3.scan mutiple artifact 4.fix global search bug 5.disable delete tag btn when remove immutable tag 6.cancel selectRow when add label or remove label;fix #11195 7.fix cron tootip --- .../artifact-list-tab.component.html | 10 ++-- .../artifact-list-tab.component.ts | 26 +++++++-- .../artifact-vulnerabilities.component.ts | 5 +- .../artifact/artifact-summary.component.html | 2 +- .../artifact-tag/artifact-tag.component.html | 4 +- .../artifact-tag.component.spec.ts | 12 ++++ .../artifact-tag/artifact-tag.component.ts | 20 ++++++- .../list-repository-ro.component.ts | 5 +- src/portal/src/i18n/lang/en-us-lang.json | 2 +- src/portal/src/i18n/lang/es-es-lang.json | 2 +- src/portal/src/i18n/lang/fr-fr-lang.json | 2 +- src/portal/src/i18n/lang/pt-br-lang.json | 2 +- .../cron-schedule.component.html | 55 ++++++++++--------- .../cron-schedule.component.scss | 1 + tests/resources/Harbor-Pages/Project.robot | 2 +- .../Harbor-Pages/Vulnerability.robot | 1 + 16 files changed, 102 insertions(+), 49 deletions(-) diff --git a/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html b/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html index ee4b3fb00..f00cb114d 100644 --- a/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html +++ b/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html @@ -91,7 +91,7 @@ [(clrDgSelected)]="selectedRow"> @@ -110,7 +110,7 @@ (click)="addLabels()"> {{'REPOSITORY.ADD_LABELS' | translate}} - +
@@ -208,17 +208,17 @@ {{'REPOSITORY.TAGS_COUNT' | translate | uppercase}} - - {{'REPOSITORY.PUSH_TIME' | translate | uppercase}} {{'REPOSITORY.PULL_TIME' | translate | uppercase}} + + {{'REPOSITORY.PUSH_TIME' | translate | uppercase}} {{tag.name}} + {{tag.pull_time === availableTime ? '':(tag.pull_time | date: 'short')}} {{tag.push_time | date: 'short'}} - {{tag.pull_time | date: 'short'}} diff --git a/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts b/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts index 5537c5f3d..21a37ecc3 100644 --- a/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts +++ b/src/portal/src/app/project/repository/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts @@ -162,6 +162,10 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { openSelectFilterPiece = false; // could Pagination filter filters: string[]; + + scanFiinishArtifactLength: number = 0; + onScanArtifactsLength: number = 0; + constructor( private errorHandlerService: ErrorHandler, private userPermissionService: UserPermissionService, @@ -731,6 +735,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { forkJoin(...this.deleteArtifactobservableLists).subscribe((deleteResult) => { let deleteSuccessList = []; let deleteErrorList = []; + this.deleteArtifactobservableLists = []; deleteResult.forEach(result => { if (!result) { // delete success @@ -739,9 +744,9 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { deleteErrorList.push(result); } }); + this.selectedRow = []; if (deleteSuccessList.length === deleteResult.length) { // all is success - this.selectedRow = []; let st: ClrDatagridStateInterface = { page: {from: 0, to: this.pageSize - 1, size: this.pageSize} }; this.clrLoad(st); } else if (deleteErrorList.length === deleteResult.length) { @@ -752,7 +757,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { // some artifact delete success but it has error delete things this.errorHandlerService.error(deleteErrorList[deleteErrorList.length - 1].error); // if delete one success refresh list - this.selectedRow = []; let st: ClrDatagridStateInterface = { page: {from: 0, to: this.pageSize - 1, size: this.pageSize} }; this.clrLoad(st); } @@ -871,10 +875,16 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { } // Trigger scan scanNow(): void { - if (this.selectedRow && this.selectedRow.length === 1) { - this.onSendingScanCommand = true; - this.channel.publishScanEvent(this.repoName + "/" + this.selectedRow[0].digest); + if (!this.selectedRow.length) { + return; } + this.scanFiinishArtifactLength = 0; + this.onScanArtifactsLength = this.selectedRow.length; + this.onSendingScanCommand = true; + this.selectedRow.forEach((data: any) => { + let digest = data.digest; + this.channel.publishScanEvent(this.repoName + "/" + digest); + }); } selectedRowHasVul(): boolean { return !!(this.selectedRow @@ -886,7 +896,11 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { return !!(artifact && artifact.addition_links && artifact.addition_links[ADDITIONS.VULNERABILITIES]); } submitFinish(e: boolean) { - this.onSendingScanCommand = e; + this.scanFiinishArtifactLength += 1; + // all selected scan action has start + if (this.scanFiinishArtifactLength === this.onScanArtifactsLength) { + this.onSendingScanCommand = e; + } } // pull command onCpError($event: any): void { diff --git a/src/portal/src/app/project/repository/artifact/artifact-additions/artifact-vulnerabilities/artifact-vulnerabilities.component.ts b/src/portal/src/app/project/repository/artifact/artifact-additions/artifact-vulnerabilities/artifact-vulnerabilities.component.ts index 544db9988..2283e698c 100644 --- a/src/portal/src/app/project/repository/artifact/artifact-additions/artifact-vulnerabilities/artifact-vulnerabilities.component.ts +++ b/src/portal/src/app/project/repository/artifact/artifact-additions/artifact-vulnerabilities/artifact-vulnerabilities.component.ts @@ -91,7 +91,10 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy { this.hasShowLoading = true; } this.additionsService.getDetailByLink(this.vulnerabilitiesLink.href) - .pipe(finalize(() => this.loading = false)) + .pipe(finalize(() => { + this.loading = false; + this.hasShowLoading = false; + })) .subscribe( res => { this.scan_overview = res; diff --git a/src/portal/src/app/project/repository/artifact/artifact-summary.component.html b/src/portal/src/app/project/repository/artifact/artifact-summary.component.html index aebe6d617..f8f90fedc 100644 --- a/src/portal/src/app/project/repository/artifact/artifact-summary.component.html +++ b/src/portal/src/app/project/repository/artifact/artifact-summary.component.html @@ -22,7 +22,7 @@ - diff --git a/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.html b/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.html index 319b39249..1f044e366 100644 --- a/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.html +++ b/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.html @@ -4,7 +4,7 @@ -
@@ -46,7 +46,7 @@ {{'REPOSITORY.IMMUTABLE' | translate}}
- +
diff --git a/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.spec.ts b/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.spec.ts index 2d322ef58..306b34483 100644 --- a/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.spec.ts +++ b/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.spec.ts @@ -10,6 +10,7 @@ import { ErrorHandler } from "../../../../../lib/utils/error-handler"; import { ArtifactService } from '../../../../../../ng-swagger-gen/services/artifact.service'; import { OperationService } from "../../../../../lib/components/operation/operation.service"; import { CURRENT_BASE_HREF } from "../../../../../lib/utils/utils"; +import { USERSTATICPERMISSION, UserPermissionService, UserPermissionDefaultService } from '../../../../../lib/services'; describe('ArtifactTagComponent', () => { @@ -25,6 +26,11 @@ describe('ArtifactTagComponent', () => { const config: IServiceConfig = { repositoryBaseEndpoint: CURRENT_BASE_HREF + "/repositories/testing" }; + let userPermissionService; + const permissions = [ + { resource: USERSTATICPERMISSION.REPOSITORY_TAG.KEY, action: USERSTATICPERMISSION.REPOSITORY_TAG.VALUE.DELETE }, + ]; + let mockHasDeleteImagePermission: boolean = true; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ @@ -41,6 +47,7 @@ describe('ArtifactTagComponent', () => { { provide: SERVICE_CONFIG, useValue: config }, { provide: mockErrorHandler, useValue: ErrorHandler }, { provide: ArtifactService, useValue: mockArtifactService }, + { provide: UserPermissionService, useClass: UserPermissionDefaultService }, { provide: OperationService }, ] }) @@ -50,6 +57,11 @@ describe('ArtifactTagComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ArtifactTagComponent); component = fixture.componentInstance; + userPermissionService = fixture.debugElement.injector.get(UserPermissionService); + spyOn(userPermissionService, "hasProjectPermissions") + .withArgs(component.projectId, permissions) + .and.returnValue(of([ + mockHasDeleteImagePermission])); fixture.detectChanges(); }); diff --git a/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.ts b/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.ts index b036d4aab..a1f5ad539 100644 --- a/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.ts +++ b/src/portal/src/app/project/repository/artifact/artifact-tag/artifact-tag.component.ts @@ -17,7 +17,10 @@ import { errorHandler } from "../../../../../lib/utils/shared/shared.utils"; import { ArtifactFront as Artifact } from "../artifact"; import { ArtifactService } from '../../../../../../ng-swagger-gen/services/artifact.service'; import { Tag } from '../../../../../../ng-swagger-gen/models/tag'; +import { + UserPermissionService, USERSTATICPERMISSION +} from "../../../../../lib/services"; class InitTag { name = ""; } @@ -30,6 +33,7 @@ class InitTag { export class ArtifactTagComponent implements OnInit { @Input() artifactDetails: Artifact; @Input() projectName: string; + @Input() projectId: number; @Input() repositoryName: string; @Output() refreshArtifact = new EventEmitter(); newTagName = new InitTag(); @@ -43,15 +47,25 @@ export class ArtifactTagComponent implements OnInit { availableTime = AVAILABLE_TIME; @ViewChild("confirmationDialog", { static: false }) confirmationDialog: ConfirmationDialogComponent; + hasDeleteTagPermission: boolean; constructor( private operationService: OperationService, private artifactService: ArtifactService, private translateService: TranslateService, + private userPermissionService: UserPermissionService, private errorHandlerService: ErrorHandler ) { } - ngOnInit() { + this.getImagePermissionRule(this.projectId); + } + getImagePermissionRule(projectId: number): void { + const permissions = [ + { resource: USERSTATICPERMISSION.REPOSITORY_TAG.KEY, action: USERSTATICPERMISSION.REPOSITORY_TAG.VALUE.DELETE } + ]; + this.userPermissionService.hasProjectPermissions(this.projectId, permissions).subscribe((results: Array) => { + this.hasDeleteTagPermission = results[0]; + }, error => this.errorHandlerService.error(error)); } addTag() { @@ -166,4 +180,8 @@ export class ArtifactTagComponent implements OnInit { this.openTag = !this.openTag; this.newTagformShow = false; } + hasImmutableOnTag(): boolean { + return this.selectedRow.some((artifact) => artifact.immutable); + } + } diff --git a/src/portal/src/app/shared/list-repository-ro/list-repository-ro.component.ts b/src/portal/src/app/shared/list-repository-ro/list-repository-ro.component.ts index 1a3de17ca..a3c24f029 100644 --- a/src/portal/src/app/shared/list-repository-ro/list-repository-ro.component.ts +++ b/src/portal/src/app/shared/list-repository-ro/list-repository-ro.component.ts @@ -68,8 +68,9 @@ export class ListRepositoryROComponent implements OnInit, OnDestroy { public gotoLink(projectId: number, repoName: string): void { this.searchTrigger.closeSearch(true); - - let linkUrl = ['harbor', 'tags', projectId, repoName]; + let projectName = repoName.split('/')[0]; + let repositorieName = projectName ? repoName.split(`${projectName}/`)[1] : repoName; + let linkUrl = ['harbor', 'projects', projectId, 'repositories', repositorieName ]; this.router.navigate(linkUrl); } diff --git a/src/portal/src/i18n/lang/en-us-lang.json b/src/portal/src/i18n/lang/en-us-lang.json index 0d7568116..635068bec 100644 --- a/src/portal/src/i18n/lang/en-us-lang.json +++ b/src/portal/src/i18n/lang/en-us-lang.json @@ -693,7 +693,7 @@ "ADD_LABEL_TO_IMAGE": "Add labels to this image", "FILTER_BY_LABEL": "Filter images by label", "FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label", - "ADD_LABELS": "Add labels", + "ADD_LABELS": "Add Labels", "RETAG": "Copy", "ACTION": "ACTION", "DEPLOY": "DEPLOY", diff --git a/src/portal/src/i18n/lang/es-es-lang.json b/src/portal/src/i18n/lang/es-es-lang.json index 5ba36407b..d72c03634 100644 --- a/src/portal/src/i18n/lang/es-es-lang.json +++ b/src/portal/src/i18n/lang/es-es-lang.json @@ -694,7 +694,7 @@ "ADD_LABEL_TO_IMAGE": "Add labels to this image", "FILTER_BY_LABEL": "Filter images by label", "FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label", - "ADD_LABELS": "Add labels", + "ADD_LABELS": "Add Labels", "RETAG": "Copy", "ACTION": "ACTION", "DEPLOY": "DEPLOY", diff --git a/src/portal/src/i18n/lang/fr-fr-lang.json b/src/portal/src/i18n/lang/fr-fr-lang.json index aa1b63a77..9898a5098 100644 --- a/src/portal/src/i18n/lang/fr-fr-lang.json +++ b/src/portal/src/i18n/lang/fr-fr-lang.json @@ -680,7 +680,7 @@ "ADD_LABEL_TO_IMAGE": "Add labels to this image", "FILTER_BY_LABEL": "Filter images by label", "FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label", - "ADD_LABELS": "Add labels", + "ADD_LABELS": "Add Labels", "RETAG": "Copy", "ACTION": "ACTION", "DEPLOY": "DEPLOY", diff --git a/src/portal/src/i18n/lang/pt-br-lang.json b/src/portal/src/i18n/lang/pt-br-lang.json index b96703a76..61dc1250c 100644 --- a/src/portal/src/i18n/lang/pt-br-lang.json +++ b/src/portal/src/i18n/lang/pt-br-lang.json @@ -693,7 +693,7 @@ "ADD_LABEL_TO_IMAGE": "Adicionar labels a essa imagem", "FILTER_BY_LABEL": "Filtrar imagens por label", "FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label", - "ADD_LABELS": "Adicionar labels", + "ADD_LABELS": "Adicionar Labels", "RETAG": "Copy", "ACTION": "AÇÃO", "DEPLOY": "DEPLOY", diff --git a/src/portal/src/lib/components/cron-schedule/cron-schedule.component.html b/src/portal/src/lib/components/cron-schedule/cron-schedule.component.html index 05a771cfd..751a29753 100644 --- a/src/portal/src/lib/components/cron-schedule/cron-schedule.component.html +++ b/src/portal/src/lib/components/cron-schedule/cron-schedule.component.html @@ -2,29 +2,33 @@ -
{{ labelEdit | translate }}
- @@ -34,27 +38,26 @@
{{ "SCHEDULE.CRON" | translate }}
-
-
-
+ \ No newline at end of file diff --git a/src/portal/src/lib/components/cron-schedule/cron-schedule.component.scss b/src/portal/src/lib/components/cron-schedule/cron-schedule.component.scss index 661ce8ec4..9bf73e162 100644 --- a/src/portal/src/lib/components/cron-schedule/cron-schedule.component.scss +++ b/src/portal/src/lib/components/cron-schedule/cron-schedule.component.scss @@ -47,6 +47,7 @@ .cron-tooltip { color: gray; cursor: default; + position: absolute; .table-box { width: 20rem; } diff --git a/tests/resources/Harbor-Pages/Project.robot b/tests/resources/Harbor-Pages/Project.robot index 62aed20a2..dbc08608f 100644 --- a/tests/resources/Harbor-Pages/Project.robot +++ b/tests/resources/Harbor-Pages/Project.robot @@ -248,7 +248,7 @@ Add Labels To Tag Retry Element Click xpath=//clr-dg-row[contains(.,'${tagName}')]//label Capture Page Screenshot add_${labelName}.png Retry Element Click xpath=//clr-dg-action-bar//clr-dropdown//span - Retry Element Click xpath=//clr-dropdown-menu//clr-dropdown//button[contains(.,'Add labels')] + Retry Element Click xpath=//clr-dropdown-menu//clr-dropdown//button[contains(.,'Add Labels')] Retry Element Click xpath=//clr-dropdown//div//label[contains(.,'${labelName}')] Retry Wait Until Page Contains Element xpath=//clr-dg-row//label[contains(.,'${labelName}')] diff --git a/tests/resources/Harbor-Pages/Vulnerability.robot b/tests/resources/Harbor-Pages/Vulnerability.robot index e966bab36..c08ca7356 100644 --- a/tests/resources/Harbor-Pages/Vulnerability.robot +++ b/tests/resources/Harbor-Pages/Vulnerability.robot @@ -76,6 +76,7 @@ Switch To Scanners Page Should Display The Default Clair Scanner Retry Wait Until Page Contains Element //clr-datagrid//clr-dg-row//clr-dg-cell[contains(.,'Clair')]//span[contains(.,'Default')] + Clair Is Immutable Scanner Retry Element Click //clr-dg-row[contains(.,'Clair')]//clr-radio-wrapper/label Retry Double Keywords When Error Retry Element Click ${scanner_action_xpath} Retry Wait Until Page Contains Element ${delete_scanner_action_xpath}