Support accessory recursion for artifact list (#18366)

1. Update accessory UI to support recursion

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Shijun Sun 2023-03-17 13:01:24 +08:00 committed by GitHub
parent 321d8a0885
commit 53d86f872e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 32 deletions

View File

@ -546,7 +546,6 @@
ngProjectAs="clr-dg-row-detail"
*ngIf="artifact?.accessories?.length">
<sub-accessories
(deleteAccessory)="deleteAccessory($event)"
[projectName]="projectName"
[repositoryName]="repoName"
[artifactDigest]="artifact?.digest"

View File

@ -189,6 +189,7 @@ export class ArtifactListTabComponent
);
copiedHiddenArray: boolean[] = [];
private _hasViewInit: boolean = false;
deleteAccessorySub: Subscription;
constructor(
private errorHandlerService: ErrorHandler,
private artifactService: ArtifactService,
@ -242,6 +243,14 @@ export class ArtifactListTabComponent
}
);
}
if (!this.deleteAccessorySub) {
this.deleteAccessorySub = this.eventService.subscribe(
HarborEvent.DELETE_ACCESSORY,
(a: Accessory) => {
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;

View File

@ -16,10 +16,14 @@
</button>
</clr-dg-action-overflow>
<clr-dg-cell class="relative">
<!--it will cause a ExpressionChangedAfterItHasBeenCheckedError when read datagrid['el']?.nativeElement?.offsetHeight so
use OnPush Strategy to avoid ExpressionChangedAfterItHasBeenCheckedError-->
<hr
class="y-dash-line"
*ngIf="i === displayedAccessories?.length - 1 && viewInit"
[style.height.px]="dashLineHeight" />
[hidden]="i !== displayedAccessories?.length - 1"
[style.height.px]="
datagrid['el']?.nativeElement?.offsetHeight || 0
" />
<hr class="x-dash-line" />
<div class="cell">
<div
@ -55,6 +59,17 @@
{{ a.creation_time | harborDatetime : 'short' }}
</div>
</clr-dg-cell>
<ng-container
ngProjectAs="clr-dg-row-detail"
*ngIf="a?.accessories?.length">
<sub-accessories
[projectName]="projectName"
[repositoryName]="repositoryName"
[artifactDigest]="a?.digest"
[total]="a?.accessoryNumber"
[accessories]="a?.accessories"
*clrIfExpanded></sub-accessories>
</ng-container>
</clr-dg-row>
<clr-dg-footer *ngIf="total > pageSize">
<clr-dg-pagination

View File

@ -64,6 +64,9 @@ describe('SubAccessoriesComponent', () => {
listAccessories() {
return of(page2).pipe(delay(0));
},
listAccessoriesResponse() {
return of({}).pipe(delay(0));
},
};
let component: SubAccessoriesComponent;

View File

@ -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<Accessory> = new EventEmitter<Accessory>();
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;
}
}

View File

@ -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<{

View File

@ -79,4 +79,5 @@ export enum HarborEvent {
STOP_SCAN_ARTIFACT = 'stopScanArtifact',
UPDATE_VULNERABILITY_INFO = 'UpdateVulnerabilityInfo',
REFRESH_EXPORT_JOBS = 'refreshExportJobs',
DELETE_ACCESSORY = 'deleteAccessory',
}