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 b21734df9..61a60f504 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 @@ -546,7 +546,6 @@ ngProjectAs="clr-dg-row-detail" *ngIf="artifact?.accessories?.length"> { + this.deleteAccessory(a); + } + ); + } } ngAfterViewInit() { @@ -253,6 +262,10 @@ export class ArtifactListTabComponent this.updateArtifactSub.unsubscribe(); this.updateArtifactSub = null; } + if (this.deleteAccessorySub) { + this.deleteAccessorySub.unsubscribe(); + this.deleteAccessorySub = null; + } } get withNotary(): boolean { return this.appConfigService.getConfig()?.with_notary; diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.html index fda12da8c..f4f993329 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.html @@ -16,10 +16,14 @@ +
+ [hidden]="i !== displayedAccessories?.length - 1" + [style.height.px]=" + datagrid['el']?.nativeElement?.offsetHeight || 0 + " />
+ + + { listAccessories() { return of(page2).pipe(delay(0)); }, + listAccessoriesResponse() { + return of({}).pipe(delay(0)); + }, }; let component: SubAccessoriesComponent; diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.ts index 96c369ea9..9c700e932 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/sub-accessories/sub-accessories.component.ts @@ -1,10 +1,10 @@ import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, Component, - EventEmitter, Input, OnInit, - Output, - ViewChild, } from '@angular/core'; import { clone, @@ -22,8 +22,15 @@ import { ErrorHandler } from '../../../../../../../../shared/units/error-handler import { finalize } from 'rxjs/operators'; import { SafeUrl } from '@angular/platform-browser'; import { ArtifactService } from '../../../../artifact.service'; -import { AccessoryQueryParams, artifactDefault } from '../../../../artifact'; -import { ClrDatagrid } from '@clr/angular'; +import { + AccessoryFront, + AccessoryQueryParams, + artifactDefault, +} from '../../../../artifact'; +import { + EventService, + HarborEvent, +} from '../../../../../../../../services/event-service/event.service'; export const ACCESSORY_PAGE_SIZE: number = 5; @@ -31,8 +38,9 @@ export const ACCESSORY_PAGE_SIZE: number = 5; selector: 'sub-accessories', templateUrl: 'sub-accessories.component.html', styleUrls: ['./sub-accessories.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, // use OnPush Strategy to avoid ExpressionChangedAfterItHasBeenCheckedError }) -export class SubAccessoriesComponent implements OnInit { +export class SubAccessoriesComponent implements OnInit, AfterViewInit { @Input() projectName: string; @Input() @@ -41,32 +49,29 @@ export class SubAccessoriesComponent implements OnInit { artifactDigest: string; @Input() accessories: Accessory[] = []; - @Output() - deleteAccessory: EventEmitter = new EventEmitter(); currentPage: number = 1; @Input() total: number = 0; pageSize: number = ACCESSORY_PAGE_SIZE; page: number = 1; - displayedAccessories: Accessory[] = []; + displayedAccessories: AccessoryFront[] = []; loading: boolean = false; - @ViewChild('datagrid') - datagrid: ClrDatagrid; - viewInit: boolean = false; constructor( private activatedRoute: ActivatedRoute, private router: Router, private newArtifactService: NewArtifactService, private artifactService: ArtifactService, - private errorHandlerService: ErrorHandler + private errorHandlerService: ErrorHandler, + private cdf: ChangeDetectorRef, + private event: EventService ) {} + ngAfterViewInit(): void { + this.cdf.detectChanges(); + } + ngOnInit(): void { this.displayedAccessories = clone(this.accessories); - // avoid ng checking error - setTimeout(() => { - this.viewInit = true; - }); } size(size: number) { return formatSize(size.toString()); @@ -103,13 +108,14 @@ export class SubAccessoriesComponent implements OnInit { } delete(a: Accessory) { - this.deleteAccessory.emit(a); + this.event.publish(HarborEvent.DELETE_ACCESSORY, a); } clrLoad() { if (this.currentPage === 1) { this.displayedAccessories = clone(this.accessories); this.getIconFromBackend(); + this.getAccessoriesAsync(this.displayedAccessories); return; } this.loading = true; @@ -126,7 +132,9 @@ export class SubAccessoriesComponent implements OnInit { .subscribe( res => { this.displayedAccessories = res; + this.cdf.detectChanges(); this.getIconFromBackend(); + this.getAccessoriesAsync(this.displayedAccessories); }, error => { this.errorHandlerService.error(error); @@ -139,14 +147,37 @@ export class SubAccessoriesComponent implements OnInit { } } - get dashLineHeight() { - if ( - this.datagrid && - this.datagrid['el'] && - this.datagrid['el']?.nativeElement?.offsetHeight - ) { - return this.datagrid['el'].nativeElement?.offsetHeight; + // get accessories + getAccessoriesAsync(artifacts: AccessoryFront[]) { + if (artifacts && artifacts.length) { + artifacts.forEach(item => { + const listTagParams: NewArtifactService.ListAccessoriesParams = + { + projectName: this.projectName, + repositoryName: dbEncodeURIComponent( + this.repositoryName + ), + reference: item.digest, + page: 1, + pageSize: ACCESSORY_PAGE_SIZE, + }; + this.newArtifactService + .listAccessoriesResponse(listTagParams) + .subscribe(res => { + if (res.headers) { + let xHeader: string = + res.headers.get('x-total-count'); + if (xHeader) { + item.accessoryNumber = Number.parseInt( + xHeader, + 10 + ); + } + } + item.accessories = res.body; + this.cdf.detectChanges(); + }); + }); } - return 0; } } diff --git a/src/portal/src/app/base/project/repository/artifact/artifact.ts b/src/portal/src/app/base/project/repository/artifact/artifact.ts index 776a625ba..25a2036e3 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact.ts @@ -14,9 +14,9 @@ export interface ArtifactFront extends Artifact { } export interface AccessoryFront extends Accessory { - pullCommand?: string; - tagNumber?: number; - scan_overview?: any; + coSigned?: string; + accessoryNumber?: number; + accessories?: any; } export const multipleFilter: Array<{ diff --git a/src/portal/src/app/services/event-service/event.service.ts b/src/portal/src/app/services/event-service/event.service.ts index dedca6de2..fe492e32c 100644 --- a/src/portal/src/app/services/event-service/event.service.ts +++ b/src/portal/src/app/services/event-service/event.service.ts @@ -79,4 +79,5 @@ export enum HarborEvent { STOP_SCAN_ARTIFACT = 'stopScanArtifact', UPDATE_VULNERABILITY_INFO = 'UpdateVulnerabilityInfo', REFRESH_EXPORT_JOBS = 'refreshExportJobs', + DELETE_ACCESSORY = 'deleteAccessory', }