mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-23 09:08:26 +01:00
Update the style for severity (#19525)
1.Related issue #19249 Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
b337f51e7e
commit
d0a9754786
@ -63,3 +63,7 @@
|
||||
.min-width {
|
||||
min-width: 9rem !important;
|
||||
}
|
||||
|
||||
.label {
|
||||
min-width: 3rem;
|
||||
}
|
||||
|
@ -93,3 +93,12 @@ export function getRepoLink(proId: number | string, repoName: string): any {
|
||||
}
|
||||
|
||||
export const CVSS3_REG = /^([0-9]|10)(\.\d)?$/;
|
||||
|
||||
export enum SeverityColors {
|
||||
CRITICAL = '#FF4D2E',
|
||||
HIGH = '#FF8F3D',
|
||||
MEDIUM = '#FFCE66',
|
||||
LOW = '#FFF1AD',
|
||||
NONE = '#2EC0FF',
|
||||
NA = 'gray',
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import {
|
||||
} from '@angular/core';
|
||||
import { DangerousArtifact } from '../../../../../../../ng-swagger-gen/models/dangerous-artifact';
|
||||
import * as echarts from 'echarts/core';
|
||||
import { SeverityColors } from '../security-hub.interface';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-single-bar',
|
||||
@ -23,6 +25,8 @@ export class SingleBarComponent implements OnChanges {
|
||||
@ViewChild('container', { static: true })
|
||||
container: ElementRef;
|
||||
|
||||
constructor(private translate: TranslateService) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes && changes['dangerousArtifact']) {
|
||||
this.initChart();
|
||||
@ -31,74 +35,87 @@ export class SingleBarComponent implements OnChanges {
|
||||
|
||||
initChart() {
|
||||
const chart = echarts.init(this.container.nativeElement);
|
||||
chart.setOption({
|
||||
color: ['red', '#e64524', 'orange'],
|
||||
title: {
|
||||
text: '',
|
||||
},
|
||||
tooltip: {
|
||||
formatter: '{b}: {c}',
|
||||
textStyle: {
|
||||
fontSize: '12px',
|
||||
whiteSpace: 'nowrap',
|
||||
const [severity, c, h, m] = [
|
||||
'VULNERABILITY.GRID.COLUMN_SEVERITY',
|
||||
'VULNERABILITY.SEVERITY.CRITICAL',
|
||||
'VULNERABILITY.SEVERITY.HIGH',
|
||||
'VULNERABILITY.SEVERITY.MEDIUM',
|
||||
];
|
||||
this.translate.get([severity, c, h, m]).subscribe(res => {
|
||||
chart.setOption({
|
||||
color: [
|
||||
SeverityColors.CRITICAL,
|
||||
SeverityColors.HIGH,
|
||||
SeverityColors.MEDIUM,
|
||||
],
|
||||
title: {
|
||||
text: '',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '65%',
|
||||
name: 'Severity',
|
||||
// adjust the start angle
|
||||
startAngle: 180,
|
||||
itemStyle: {
|
||||
borderRadius: 2,
|
||||
borderWidth: 1,
|
||||
tooltip: {
|
||||
formatter: '{b}: {c}',
|
||||
textStyle: {
|
||||
fontSize: '12px',
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: '{c}',
|
||||
fontSize: '9px',
|
||||
},
|
||||
data: [
|
||||
{
|
||||
name: 'Critical',
|
||||
value: this.dangerousArtifact?.critical_cnt || 0,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '65%',
|
||||
name: res[severity],
|
||||
// adjust the start angle
|
||||
startAngle: 180,
|
||||
itemStyle: {
|
||||
borderRadius: 2,
|
||||
borderWidth: 1,
|
||||
},
|
||||
{
|
||||
name: 'High',
|
||||
value: this.dangerousArtifact?.high_cnt || 0,
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
value: this.dangerousArtifact?.medium_cnt || 0,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: '{c}',
|
||||
fontSize: '9px',
|
||||
},
|
||||
{
|
||||
// make a record to fill the bottom 50%
|
||||
value:
|
||||
this.dangerousArtifact?.critical_cnt +
|
||||
this.dangerousArtifact?.high_cnt +
|
||||
this.dangerousArtifact?.medium_cnt || 0,
|
||||
itemStyle: {
|
||||
// stop the chart from rendering this piece
|
||||
color: 'none',
|
||||
decal: {
|
||||
symbol: 'none',
|
||||
data: [
|
||||
{
|
||||
name: res[c],
|
||||
value:
|
||||
this.dangerousArtifact?.critical_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: res[h],
|
||||
value: this.dangerousArtifact?.high_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: res[m],
|
||||
value: this.dangerousArtifact?.medium_cnt || 0,
|
||||
},
|
||||
{
|
||||
// make a record to fill the bottom 50%
|
||||
value:
|
||||
this.dangerousArtifact?.critical_cnt +
|
||||
this.dangerousArtifact?.high_cnt +
|
||||
this.dangerousArtifact?.medium_cnt || 0,
|
||||
itemStyle: {
|
||||
// stop the chart from rendering this piece
|
||||
color: 'none',
|
||||
decal: {
|
||||
symbol: 'none',
|
||||
},
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -106,3 +106,7 @@ $row-height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
min-width: 3rem;
|
||||
}
|
||||
|
@ -11,7 +11,12 @@ import {
|
||||
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, severityText, VUL_ID } from '../security-hub.interface';
|
||||
import {
|
||||
getDigestLink,
|
||||
SeverityColors,
|
||||
severityText,
|
||||
VUL_ID,
|
||||
} from '../security-hub.interface';
|
||||
import { HAS_STYLE_MODE, StyleMode } from '../../../../../services/theme';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
@ -97,7 +102,14 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
|
||||
];
|
||||
this.translate.get([severity, c, h, m, l, n, u]).subscribe(res => {
|
||||
this.chart.setOption({
|
||||
color: ['red', '#e64524', 'orange', '#007CBB', 'grey', 'green'],
|
||||
color: [
|
||||
SeverityColors.CRITICAL,
|
||||
SeverityColors.HIGH,
|
||||
SeverityColors.MEDIUM,
|
||||
SeverityColors.LOW,
|
||||
SeverityColors.NA,
|
||||
SeverityColors.NONE,
|
||||
],
|
||||
title: {
|
||||
text: '',
|
||||
},
|
||||
|
@ -58,3 +58,7 @@
|
||||
.mt-5px {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.label {
|
||||
min-width: 3rem;
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import { BuildHistoryComponent } from './artifact-additions/build-history/build-
|
||||
import { ArtifactVulnerabilitiesComponent } from './artifact-additions/artifact-vulnerabilities/artifact-vulnerabilities.component';
|
||||
import { ArtifactDefaultService, ArtifactService } from './artifact.service';
|
||||
import { ArtifactDetailRoutingResolverService } from '../../../../services/routing-resolvers/artifact-detail-routing-resolver.service';
|
||||
import { ResultTipComponent } from './vulnerability-scanning/result-tip.component';
|
||||
import { ResultBarChartComponent } from './vulnerability-scanning/result-bar-chart.component';
|
||||
import { ResultTipHistogramComponent } from './vulnerability-scanning/result-tip-histogram/result-tip-histogram.component';
|
||||
import { HistogramChartComponent } from './vulnerability-scanning/histogram-chart/histogram-chart.component';
|
||||
@ -80,7 +79,6 @@ const routes: Routes = [
|
||||
DependenciesComponent,
|
||||
BuildHistoryComponent,
|
||||
ArtifactVulnerabilitiesComponent,
|
||||
ResultTipComponent,
|
||||
ResultBarChartComponent,
|
||||
ResultTipHistogramComponent,
|
||||
HistogramChartComponent,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ResultBarChartComponent } from './result-bar-chart.component';
|
||||
import { ResultTipComponent } from './result-tip.component';
|
||||
import { ResultTipHistogramComponent } from './result-tip-histogram/result-tip-histogram.component';
|
||||
import { HistogramChartComponent } from './histogram-chart/histogram-chart.component';
|
||||
import {
|
||||
@ -35,7 +34,6 @@ describe('ResultBarChartComponent (inline template)', () => {
|
||||
imports: [SharedTestingModule],
|
||||
declarations: [
|
||||
ResultBarChartComponent,
|
||||
ResultTipComponent,
|
||||
ResultTipHistogramComponent,
|
||||
HistogramChartComponent,
|
||||
],
|
||||
|
@ -125,21 +125,10 @@ $twenty-two-pixel: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.label.label-medium {
|
||||
background-color: #ffe4a9;
|
||||
border: 1px solid orange;
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.tip-icon-medium {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.label.label-low {
|
||||
background: rgb(251 255 0 / 38%);
|
||||
color: #c5c50b;
|
||||
border: 1px solid #e6e63f;
|
||||
}
|
||||
|
||||
.tip-icon-low {
|
||||
color: #007CBB;
|
||||
@ -178,30 +167,6 @@ hr {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.shadow-critical {
|
||||
box-shadow: 1px -1px 1px red;
|
||||
}
|
||||
|
||||
.shadow-high {
|
||||
box-shadow: 1px -1px 1px #e64524;
|
||||
}
|
||||
|
||||
.shadow-medium {
|
||||
box-shadow: 1px -1px 1px orange;
|
||||
}
|
||||
|
||||
.shadow-low {
|
||||
box-shadow: 1px -1px 1px #007CBB;
|
||||
}
|
||||
|
||||
.shadow-none {
|
||||
box-shadow: 1px -1px 1px green;
|
||||
}
|
||||
|
||||
.shadow-unknown {
|
||||
box-shadow: 1px -1px 1px gray;
|
||||
}
|
||||
|
||||
.w-360 {
|
||||
width: 360px !important;
|
||||
}
|
||||
@ -248,23 +213,23 @@ hr {
|
||||
}
|
||||
|
||||
.level-critical {
|
||||
background:red;
|
||||
color:red;
|
||||
background:#FF4D2E;
|
||||
color:#FF4D2E;
|
||||
}
|
||||
|
||||
.level-high {
|
||||
background:#e64524;
|
||||
color:#e64524;
|
||||
background:#FF8F3D;
|
||||
color:#FF8F3D;
|
||||
}
|
||||
|
||||
.level-medium {
|
||||
background-color: orange;
|
||||
color:orange;
|
||||
background-color: #FFCE66;
|
||||
color:#FFCE66;
|
||||
}
|
||||
|
||||
.level-low {
|
||||
background: #007CBB;
|
||||
color:#007CBB;
|
||||
background: #FFF1AD;
|
||||
color:#FFF1AD;
|
||||
}
|
||||
|
||||
.level-none {
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
VULNERABILITY_SEVERITY,
|
||||
} from '../../../../../../shared/units/utils';
|
||||
import { HAS_STYLE_MODE, StyleMode } from '../../../../../../services/theme';
|
||||
import { SeverityColors } from '../../../../../left-side-nav/interrogation-services/vulnerability-database/security-hub.interface';
|
||||
|
||||
const MIN = 60;
|
||||
const MIN_STR = 'min ';
|
||||
@ -229,27 +230,27 @@ export class ResultTipHistogramComponent implements OnInit {
|
||||
{
|
||||
text: 'VULNERABILITY.SEVERITY.CRITICAL',
|
||||
value: this.criticalCount ? this.criticalCount : 0,
|
||||
color: 'red',
|
||||
color: SeverityColors.CRITICAL,
|
||||
},
|
||||
{
|
||||
text: 'VULNERABILITY.SEVERITY.HIGH',
|
||||
value: this.highCount ? this.highCount : 0,
|
||||
color: '#e64524',
|
||||
color: SeverityColors.HIGH,
|
||||
},
|
||||
{
|
||||
text: 'VULNERABILITY.SEVERITY.MEDIUM',
|
||||
value: this.mediumCount ? this.mediumCount : 0,
|
||||
color: 'orange',
|
||||
color: SeverityColors.MEDIUM,
|
||||
},
|
||||
{
|
||||
text: 'VULNERABILITY.SEVERITY.LOW',
|
||||
value: this.lowCount ? this.lowCount : 0,
|
||||
color: '#007CBB',
|
||||
color: SeverityColors.LOW,
|
||||
},
|
||||
{
|
||||
text: 'VULNERABILITY.SEVERITY.NONE',
|
||||
value: this.noneCount ? this.noneCount : 0,
|
||||
color: 'grey',
|
||||
color: SeverityColors.NA,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -1,176 +0,0 @@
|
||||
<div class="tip-wrapper tip-position" [style.width]="maxWidth">
|
||||
<clr-tooltip>
|
||||
<div clrTooltipTrigger class="tip-block">
|
||||
<div
|
||||
class="tip-wrapper bar-block-high"
|
||||
[style.width]="tipWidth(5)"></div>
|
||||
<div
|
||||
class="tip-wrapper bar-block-medium"
|
||||
[style.width]="tipWidth(4)"></div>
|
||||
<div
|
||||
class="tip-wrapper bar-block-low"
|
||||
[style.width]="tipWidth(3)"></div>
|
||||
<div
|
||||
class="tip-wrapper bar-block-unknown"
|
||||
[style.width]="tipWidth(2)"></div>
|
||||
<div
|
||||
class="tip-wrapper bar-block-none"
|
||||
[style.width]="tipWidth(1)"></div>
|
||||
</div>
|
||||
<clr-tooltip-content
|
||||
[clrPosition]="'right'"
|
||||
[clrSize]="'lg'"
|
||||
*clrIfOpen>
|
||||
<div [ngSwitch]="scanLevel" class="bar-tooltip-font-larger">
|
||||
<ng-template [ngSwitchCase]="5">
|
||||
<clr-icon
|
||||
shape="exclamation-circle"
|
||||
class="is-error"
|
||||
size="32"></clr-icon>
|
||||
<span
|
||||
>{{ 'VULNERABILITY.OVERALL_SEVERITY' | translate }}
|
||||
<span class="font-weight-600">{{
|
||||
'VULNERABILITY.SEVERITY.HIGH'
|
||||
| translate
|
||||
| titlecase
|
||||
}}</span></span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template [ngSwitchCase]="4">
|
||||
<clr-icon
|
||||
*ngIf="hasMedium"
|
||||
shape="exclamation-triangle"
|
||||
class="tip-icon-medium"
|
||||
size="30"></clr-icon>
|
||||
<span
|
||||
>{{ 'VULNERABILITY.OVERALL_SEVERITY' | translate }}
|
||||
<span class="font-weight-600">{{
|
||||
'VULNERABILITY.SEVERITY.MEDIUM'
|
||||
| translate
|
||||
| titlecase
|
||||
}}</span></span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template [ngSwitchCase]="3">
|
||||
<clr-icon
|
||||
shape="play"
|
||||
class="tip-icon-low rotate-90"
|
||||
size="28"></clr-icon>
|
||||
<span
|
||||
>{{ 'VULNERABILITY.OVERALL_SEVERITY' | translate }}
|
||||
<span class="font-weight-600">{{
|
||||
'VULNERABILITY.SEVERITY.LOW' | translate | titlecase
|
||||
}}</span></span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template [ngSwitchCase]="2">
|
||||
<clr-icon
|
||||
shape="help"
|
||||
size="24"
|
||||
class="help-icon"></clr-icon>
|
||||
<span
|
||||
>{{ 'VULNERABILITY.OVERALL_SEVERITY' | translate }}
|
||||
<span class="font-weight-600">{{
|
||||
'VULNERABILITY.SEVERITY.UNKNOWN'
|
||||
| translate
|
||||
| titlecase
|
||||
}}</span></span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template [ngSwitchCase]="1">
|
||||
<clr-icon
|
||||
shape="check-circle"
|
||||
class="is-success"
|
||||
size="32"></clr-icon>
|
||||
<span>{{
|
||||
'VULNERABILITY.NO_VULNERABILITY' | translate
|
||||
}}</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<span class="bar-tooltip-font bar-tooltip-font-title">{{
|
||||
tipTitle
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="bar-summary bar-tooltip-fon">
|
||||
<div *ngIf="hasHigh" class="bar-summary-item">
|
||||
<span
|
||||
><clr-icon
|
||||
shape="exclamation-circle"
|
||||
class="is-error"
|
||||
size="24"></clr-icon
|
||||
></span>
|
||||
<span>{{ highCount }}</span
|
||||
><span
|
||||
>{{ getPackageText(highCount) | translate }}
|
||||
{{ haveText(highCount) | translate }}
|
||||
{{ 'VULNERABILITY.SEVERITY.HIGH' | translate }}
|
||||
{{ unitText(highCount) | translate }}</span
|
||||
>
|
||||
</div>
|
||||
<div *ngIf="hasMedium" class="bar-summary-item">
|
||||
<span
|
||||
><clr-icon
|
||||
*ngIf="hasMedium"
|
||||
shape="exclamation-triangle"
|
||||
class="tip-icon-medium"
|
||||
size="22"></clr-icon
|
||||
></span>
|
||||
<span>{{ mediumCount }}</span
|
||||
><span
|
||||
>{{ getPackageText(mediumCount) | translate }}
|
||||
{{ haveText(mediumCount) | translate }}
|
||||
{{ 'VULNERABILITY.SEVERITY.MEDIUM' | translate }}
|
||||
{{ unitText(mediumCount) | translate }}</span
|
||||
>
|
||||
</div>
|
||||
<div *ngIf="hasLow" class="bar-summary-item">
|
||||
<span
|
||||
><clr-icon
|
||||
shape="play"
|
||||
class="tip-icon-low rotate-90"
|
||||
size="20"></clr-icon
|
||||
></span>
|
||||
<span>{{ lowCount }}</span
|
||||
><span
|
||||
>{{ getPackageText(lowCount) | translate }}
|
||||
{{ haveText(lowCount) | translate }}
|
||||
{{ 'VULNERABILITY.SEVERITY.LOW' | translate }}
|
||||
{{ unitText(lowCount) | translate }}</span
|
||||
>
|
||||
</div>
|
||||
<div *ngIf="hasUnknown" class="bar-summary-item">
|
||||
<span><clr-icon shape="help" size="18"></clr-icon></span>
|
||||
<span>{{ unknownCount }}</span
|
||||
><span
|
||||
>{{ getPackageText(unknownCount) | translate }}
|
||||
{{ haveText(unknownCount) | translate }}
|
||||
{{ 'VULNERABILITY.SEVERITY.UNKNOWN' | translate }}
|
||||
{{ unitText(unknownCount) | translate }}</span
|
||||
>
|
||||
</div>
|
||||
<div *ngIf="hasNone" class="bar-summary-item">
|
||||
<span
|
||||
><clr-icon
|
||||
shape="check-circle"
|
||||
class="is-success"
|
||||
size="24"></clr-icon
|
||||
></span>
|
||||
<span>{{ noneCount }}</span
|
||||
><span>{{
|
||||
'VULNERABILITY.SEVERITY.NONE' | translate
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="bar-scanning-time"
|
||||
>{{ 'VULNERABILITY.CHART.SCANNING_TIME' | translate }}
|
||||
</span>
|
||||
<span>{{
|
||||
completeTimestamp | harborDatetime : 'MM/dd/y HH:mm:ss'
|
||||
}}</span>
|
||||
</div>
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</div>
|
@ -1,67 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ResultTipComponent } from './result-tip.component';
|
||||
import {
|
||||
UserPermissionDefaultService,
|
||||
UserPermissionService,
|
||||
VulnerabilitySummary,
|
||||
} from '../../../../../shared/services';
|
||||
import { VULNERABILITY_SCAN_STATUS } from '../../../../../shared/units/utils';
|
||||
import { SharedTestingModule } from '../../../../../shared/shared.module';
|
||||
|
||||
describe('ResultTipComponent (inline template)', () => {
|
||||
let component: ResultTipComponent;
|
||||
let fixture: ComponentFixture<ResultTipComponent>;
|
||||
let mockData: VulnerabilitySummary = {
|
||||
scan_status: VULNERABILITY_SCAN_STATUS.SUCCESS,
|
||||
severity: 'High',
|
||||
end_time: new Date(),
|
||||
summary: {
|
||||
total: 124,
|
||||
fixable: 50,
|
||||
summary: {
|
||||
High: 5,
|
||||
Low: 5,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SharedTestingModule],
|
||||
declarations: [ResultTipComponent],
|
||||
providers: [
|
||||
{
|
||||
provide: UserPermissionService,
|
||||
useClass: UserPermissionDefaultService,
|
||||
},
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ResultTipComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.summary = mockData;
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should reader the bar with different width', () => {
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let el: HTMLElement =
|
||||
fixture.nativeElement.querySelector('.bar-block-none');
|
||||
expect(el).not.toBeNull();
|
||||
expect(el.style.width).toEqual('0px');
|
||||
let el2: HTMLElement =
|
||||
fixture.nativeElement.querySelector('.bar-block-high');
|
||||
expect(el2).not.toBeNull();
|
||||
expect(el2.style.width).toEqual('0px');
|
||||
});
|
||||
});
|
||||
});
|
@ -1,198 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import {
|
||||
VulnerabilitySeverity,
|
||||
VulnerabilitySummary,
|
||||
} from '../../../../../shared/services';
|
||||
import { VULNERABILITY_SCAN_STATUS } from '../../../../../shared/units/utils';
|
||||
|
||||
export const MIN_TIP_WIDTH = 5;
|
||||
export const MAX_TIP_WIDTH = 100;
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-vulnerability-summary-chart',
|
||||
templateUrl: './result-tip.component.html',
|
||||
styleUrls: ['./scanning.scss'],
|
||||
})
|
||||
export class ResultTipComponent {
|
||||
_tipTitle: string = '';
|
||||
_highCount: number = 0;
|
||||
_mediumCount: number = 0;
|
||||
_lowCount: number = 0;
|
||||
_unknownCount: number = 0;
|
||||
_noneCount: number = 0;
|
||||
|
||||
totalPackages: number = 0;
|
||||
packagesWithVul: number = 0;
|
||||
|
||||
@Input() summary: VulnerabilitySummary = {
|
||||
scan_status: VULNERABILITY_SCAN_STATUS.NOT_SCANNED,
|
||||
severity: '',
|
||||
end_time: new Date(),
|
||||
};
|
||||
|
||||
get scanLevel() {
|
||||
let level;
|
||||
if (this._highCount && this._highCount >= 1) {
|
||||
level = VulnerabilitySeverity.HIGH;
|
||||
} else if (this._mediumCount && this._mediumCount >= 1) {
|
||||
level = VulnerabilitySeverity.MEDIUM;
|
||||
} else if (this._lowCount && this._lowCount >= 1) {
|
||||
level = VulnerabilitySeverity.LOW;
|
||||
} else if (this._unknownCount && this._unknownCount >= 1) {
|
||||
level = VulnerabilitySeverity.UNKNOWN;
|
||||
} else if (this.totalPackages === 0) {
|
||||
level = VulnerabilitySeverity.UNKNOWN;
|
||||
} else {
|
||||
level = VulnerabilitySeverity.NONE;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
|
||||
tipWidth(severity: VulnerabilitySeverity): string {
|
||||
let n: number = 0;
|
||||
let m: number = this.totalPackages;
|
||||
|
||||
if (m === 0) {
|
||||
// If no packages recognized, then show grey
|
||||
if (severity === VulnerabilitySeverity.UNKNOWN) {
|
||||
return MAX_TIP_WIDTH + 'px';
|
||||
} else {
|
||||
return 0 + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
switch (severity) {
|
||||
case VulnerabilitySeverity.HIGH:
|
||||
n = this.highCount;
|
||||
break;
|
||||
case VulnerabilitySeverity.MEDIUM:
|
||||
n = this.mediumCount;
|
||||
break;
|
||||
case VulnerabilitySeverity.LOW:
|
||||
n = this.lowCount;
|
||||
break;
|
||||
case VulnerabilitySeverity.UNKNOWN:
|
||||
n = this.unknownCount;
|
||||
break;
|
||||
case VulnerabilitySeverity.NONE:
|
||||
// Show all the left as green bar
|
||||
n =
|
||||
m -
|
||||
(this.highCount +
|
||||
this.mediumCount +
|
||||
this.lowCount +
|
||||
this.unknownCount);
|
||||
if (n < 0) {
|
||||
n = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
n = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
let width: number = Math.round((n / m) * MAX_TIP_WIDTH);
|
||||
if (width > 0 && width < MIN_TIP_WIDTH) {
|
||||
width = MIN_TIP_WIDTH;
|
||||
}
|
||||
|
||||
return width + 'px';
|
||||
}
|
||||
|
||||
unitText(count: number): string {
|
||||
if (count > 1) {
|
||||
return 'VULNERABILITY.PLURAL';
|
||||
}
|
||||
|
||||
return 'VULNERABILITY.SINGULAR';
|
||||
}
|
||||
|
||||
packageText(count: number): string {
|
||||
return count > 1 ? 'VULNERABILITY.PACKAGES' : 'VULNERABILITY.PACKAGE';
|
||||
}
|
||||
|
||||
getPackageText(count: number): string {
|
||||
return count > 1
|
||||
? 'VULNERABILITY.GRID.COLUMN_PACKAGES'
|
||||
: 'VULNERABILITY.GRID.COLUMN_PACKAGE';
|
||||
}
|
||||
|
||||
haveText(count: number): string {
|
||||
return count > 1 ? 'TAG.HAVE' : 'TAG.HAS';
|
||||
}
|
||||
|
||||
public get completeTimestamp(): Date {
|
||||
return this.summary && this.summary.end_time
|
||||
? this.summary.end_time
|
||||
: new Date();
|
||||
}
|
||||
|
||||
public get hasHigh(): boolean {
|
||||
return this.highCount > 0;
|
||||
}
|
||||
|
||||
public get hasMedium(): boolean {
|
||||
return this.mediumCount > 0;
|
||||
}
|
||||
|
||||
public get hasLow(): boolean {
|
||||
return this.lowCount > 0;
|
||||
}
|
||||
|
||||
public get hasUnknown(): boolean {
|
||||
return this.unknownCount > 0;
|
||||
}
|
||||
|
||||
public get hasNone(): boolean {
|
||||
return this.noneCount > 0;
|
||||
}
|
||||
|
||||
public get tipTitle(): string {
|
||||
return this._tipTitle;
|
||||
}
|
||||
|
||||
public get highCount(): number {
|
||||
return this._highCount;
|
||||
}
|
||||
|
||||
public get mediumCount(): number {
|
||||
return this._mediumCount;
|
||||
}
|
||||
|
||||
public get lowCount(): number {
|
||||
return this._lowCount;
|
||||
}
|
||||
|
||||
public get unknownCount(): number {
|
||||
return this._unknownCount;
|
||||
}
|
||||
public get noneCount(): number {
|
||||
return this._noneCount;
|
||||
}
|
||||
|
||||
public get highSuffix(): string {
|
||||
return this.unitText(this.highCount);
|
||||
}
|
||||
|
||||
public get mediumSuffix(): string {
|
||||
return this.unitText(this.mediumCount);
|
||||
}
|
||||
|
||||
public get lowSuffix(): string {
|
||||
return this.unitText(this.lowCount);
|
||||
}
|
||||
|
||||
public get unknownSuffix(): string {
|
||||
return this.unitText(this.unknownCount);
|
||||
}
|
||||
|
||||
public get noneSuffix(): string {
|
||||
return this.unitText(this.noneCount);
|
||||
}
|
||||
|
||||
public get maxWidth(): string {
|
||||
return MAX_TIP_WIDTH + 20 + 'px';
|
||||
}
|
||||
}
|
@ -44,30 +44,6 @@
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.bar-block-high {
|
||||
background-color: #e64524;
|
||||
}
|
||||
|
||||
.bar-block-medium {
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.bar-block-low {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.bar-block-none {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.bar-block-unknown {
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
.bar-tooltip-font {
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.bar-tooltip-font-title {
|
||||
font-weight: 600;
|
||||
|
Loading…
Reference in New Issue
Block a user