harbor/src/portal/src/app/base/left-side-nav/interrogation-services/vulnerability-database/vulnerability-summary/vulnerability-summary.compo...

206 lines
6.7 KiB
TypeScript

import {
Component,
ElementRef,
EventEmitter,
HostListener,
OnDestroy,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { SecurityhubService } from '../../../../../../../ng-swagger-gen/services/securityhub.service';
import { SecuritySummary } from '../../../../../../../ng-swagger-gen/models/security-summary';
import { MessageHandlerService } from '../../../../../shared/services/message-handler.service';
import {
getDigestLink,
SeverityColors,
severityText,
VUL_ID,
} from '../security-hub.interface';
import { HAS_STYLE_MODE, StyleMode } from '../../../../../services/theme';
import { Subscription } from 'rxjs';
import {
EventService,
HarborEvent,
} from '../../../../../services/event-service/event.service';
import { TranslateService } from '@ngx-translate/core';
import { DangerousArtifact } from '../../../../../../../ng-swagger-gen/models/dangerous-artifact';
import * as echarts from 'echarts/core';
@Component({
selector: 'app-vulnerability-summary',
templateUrl: './vulnerability-summary.component.html',
styleUrls: ['./vulnerability-summary.component.scss'],
})
export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
@Output()
searchCVE = new EventEmitter<string>();
@Output()
searchRepo = new EventEmitter<DangerousArtifact>();
securitySummary: SecuritySummary;
readonly vulId: string = VUL_ID;
readonly severityText = severityText;
readonly getDigestLink = getDigestLink;
harborEventSub: Subscription;
chart: any;
@ViewChild('pieChart', { static: true })
pieChartEle: ElementRef;
constructor(
private securityHubService: SecurityhubService,
private messageHandler: MessageHandlerService,
private event: EventService,
private translate: TranslateService
) {}
ngOnInit() {
this.chart = echarts.init(this.pieChartEle.nativeElement);
this.getSummary();
if (!this.harborEventSub) {
this.harborEventSub = this.event.subscribe(
HarborEvent.THEME_CHANGE,
() => {
if (this.securitySummary) {
this.setOption(this.securitySummary);
}
}
);
}
}
ngOnDestroy() {
if (this.harborEventSub) {
this.harborEventSub.unsubscribe();
this.harborEventSub = null;
}
}
getSummary() {
this.securityHubService
.getSecuritySummary({
withDangerousArtifact: true,
withDangerousCve: true,
})
.subscribe({
next: res => {
this.securitySummary = res;
this.setOption(res);
},
error: err => {
this.messageHandler.error(err);
},
});
}
setOption(summary: SecuritySummary) {
const [severity, c, h, m, l, n, u] = [
'VULNERABILITY.GRID.COLUMN_SEVERITY',
'VULNERABILITY.SEVERITY.CRITICAL',
'VULNERABILITY.SEVERITY.HIGH',
'VULNERABILITY.SEVERITY.MEDIUM',
'VULNERABILITY.SEVERITY.LOW',
'VULNERABILITY.SEVERITY.NONE',
'UNKNOWN',
];
this.translate.get([severity, c, h, m, l, n, u]).subscribe(res => {
this.chart.setOption({
color: [
SeverityColors.CRITICAL,
SeverityColors.HIGH,
SeverityColors.MEDIUM,
SeverityColors.LOW,
SeverityColors.NA,
SeverityColors.NONE,
],
title: {
text: '',
},
tooltip: {
formatter: '<b>{b}: {d}%</b>',
},
legend: {
align: 'left',
left: 5,
bottom: 5,
formatter: '{a|{name}}',
textStyle: {
color: this.getColorByTheme(),
width: 50,
backgroundColor: 'transparent',
rich: {
a: {
fontWeight: '100',
fontSize: '12px',
verticalAlign: 'bottom',
height: 12,
lineHeight: 15,
},
},
},
itemWidth: 12,
itemHeight: 12,
width: '50%',
},
series: [
{
itemStyle: {
borderRadius: 3,
borderWidth: 1,
},
label: {
show: false,
},
radius: ['50%', '80%'],
name: res[severity],
type: 'pie',
center: ['68%', '50%'],
data: [
{
name: res[c],
value: summary?.critical_cnt || 0,
},
{
name: res[h],
value: summary?.high_cnt || 0,
},
{
name: res[m],
value: summary?.medium_cnt || 0,
},
{
name: res[l],
value: summary?.low_cnt || 0,
},
{
name: res[u],
value: summary?.unknown_cnt || 0,
},
{
name: res[n],
value: summary?.none_cnt || 0,
},
],
},
],
});
});
}
searchCVEClick(cveId: string) {
this.searchCVE.emit(cveId);
}
searchRepoClick(artifact: DangerousArtifact) {
this.searchRepo.emit(artifact);
}
getColorByTheme(): string {
return localStorage?.getItem(HAS_STYLE_MODE) === StyleMode.LIGHT
? '#000'
: '#fff';
}
@HostListener('window:resize', ['$event'])
onResize(event: any) {
this.chart.resize();
}
}