mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-24 01:27:49 +01:00
Switch to a new chart library (#19262)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
aa5d9eb143
commit
e2d088987c
34
src/portal/package-lock.json
generated
34
src/portal/package-lock.json
generated
@ -25,7 +25,7 @@
|
||||
"@ngx-translate/core": "15.0.0",
|
||||
"@ngx-translate/http-loader": "8.0.0",
|
||||
"cron-validator": "^1.3.1",
|
||||
"highcharts": "^11.1.0",
|
||||
"echarts": "^5.4.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"ngx-clipboard": "^15.1.0",
|
||||
"ngx-cookie": "^6.0.1",
|
||||
@ -8126,6 +8126,20 @@
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/echarts": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.3.tgz",
|
||||
"integrity": "sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==",
|
||||
"dependencies": {
|
||||
"tslib": "2.3.0",
|
||||
"zrender": "5.4.4"
|
||||
}
|
||||
},
|
||||
"node_modules/echarts/node_modules/tslib": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -10030,11 +10044,6 @@
|
||||
"integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/highcharts": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-11.1.0.tgz",
|
||||
"integrity": "sha512-vhmqq6/frteWMx0GKYWwEFL25g4OYc7+m+9KQJb/notXbNtIb8KVy+ijOF7XAFqF165cq0pdLIePAmyFY5ph3g=="
|
||||
},
|
||||
"node_modules/hosted-git-info": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz",
|
||||
@ -19341,6 +19350,19 @@
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zrender": {
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.4.tgz",
|
||||
"integrity": "sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==",
|
||||
"dependencies": {
|
||||
"tslib": "2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zrender/node_modules/tslib": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
"@ngx-translate/core": "15.0.0",
|
||||
"@ngx-translate/http-loader": "8.0.0",
|
||||
"cron-validator": "^1.3.1",
|
||||
"highcharts": "^11.1.0",
|
||||
"echarts": "^5.4.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"ngx-clipboard": "^15.1.0",
|
||||
"ngx-cookie": "^6.0.1",
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { DangerousArtifact } from '../../../../../../../ng-swagger-gen/models/dangerous-artifact';
|
||||
import * as Highcharts from 'highcharts';
|
||||
import * as echarts from 'echarts/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-single-bar',
|
||||
@ -30,61 +30,71 @@ export class SingleBarComponent implements OnChanges {
|
||||
}
|
||||
|
||||
initChart() {
|
||||
(Highcharts as any).chart(this.container.nativeElement, {
|
||||
credits: {
|
||||
enabled: false,
|
||||
},
|
||||
chart: {
|
||||
backgroundColor: 'transparent',
|
||||
type: 'bar',
|
||||
},
|
||||
const chart = echarts.init(this.container.nativeElement);
|
||||
chart.setOption({
|
||||
color: ['red', '#e64524', 'orange'],
|
||||
title: {
|
||||
text: '',
|
||||
},
|
||||
tooltip: {
|
||||
pointFormat: '{series.data.name}{point.y}',
|
||||
style: {
|
||||
fontSize: 12,
|
||||
formatter: '{b}: {c}',
|
||||
textStyle: {
|
||||
fontSize: '12px',
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
startAngle: -90,
|
||||
endAngle: 90,
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
distance: -8,
|
||||
style: {
|
||||
fontSize: '8px',
|
||||
fontWeight: 1,
|
||||
},
|
||||
pointFormat: '{point.y}',
|
||||
},
|
||||
size: 50,
|
||||
borderWidth: 0,
|
||||
borderRadius: 2,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '65%',
|
||||
name: 'Severity',
|
||||
// adjust the start angle
|
||||
startAngle: 180,
|
||||
itemStyle: {
|
||||
borderRadius: 2,
|
||||
borderWidth: 1,
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: '{c}',
|
||||
fontSize: '9px',
|
||||
},
|
||||
data: [
|
||||
{
|
||||
name: 'Critical',
|
||||
y: this.dangerousArtifact?.critical_cnt || 0,
|
||||
color: 'red',
|
||||
value: this.dangerousArtifact?.critical_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: 'High',
|
||||
y: this.dangerousArtifact?.high_cnt || 0,
|
||||
color: '#e64524',
|
||||
value: this.dangerousArtifact?.high_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: 'Medium',
|
||||
y: this.dangerousArtifact?.medium_cnt || 0,
|
||||
color: 'orange',
|
||||
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,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -96,7 +96,7 @@
|
||||
</div>
|
||||
<div class="clr-row" [hidden]="!securitySummary?.total_vuls">
|
||||
<div class="placeholder">
|
||||
<div class="pie-chart" id="pie-chart"></div>
|
||||
<div #pieChart class="pie-chart" id="pie-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,15 +1,16 @@
|
||||
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 * as Highcharts from 'highcharts';
|
||||
import highchartsAccessibility from 'highcharts/modules/accessibility';
|
||||
import { getDigestLink, severityText, VUL_ID } from '../security-hub.interface';
|
||||
import { HAS_STYLE_MODE, StyleMode } from '../../../../../services/theme';
|
||||
import { Subscription } from 'rxjs';
|
||||
@ -19,7 +20,7 @@ import {
|
||||
} from '../../../../../services/event-service/event.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DangerousArtifact } from '../../../../../../../ng-swagger-gen/models/dangerous-artifact';
|
||||
highchartsAccessibility(Highcharts);
|
||||
import * as echarts from 'echarts/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-vulnerability-summary',
|
||||
@ -36,6 +37,9 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
|
||||
readonly severityText = severityText;
|
||||
readonly getDigestLink = getDigestLink;
|
||||
harborEventSub: Subscription;
|
||||
chart: any;
|
||||
@ViewChild('pieChart', { static: true })
|
||||
pieChartEle: ElementRef;
|
||||
constructor(
|
||||
private securityHubService: SecurityhubService,
|
||||
private messageHandler: MessageHandlerService,
|
||||
@ -44,6 +48,7 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.chart = echarts.init(this.pieChartEle.nativeElement);
|
||||
this.getSummary();
|
||||
if (!this.harborEventSub) {
|
||||
this.harborEventSub = this.event.subscribe(
|
||||
@ -91,79 +96,74 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
|
||||
'UNKNOWN',
|
||||
];
|
||||
this.translate.get([severity, c, h, m, l, n, u]).subscribe(res => {
|
||||
Highcharts.chart('pie-chart', {
|
||||
credits: {
|
||||
enabled: false,
|
||||
},
|
||||
chart: {
|
||||
backgroundColor: 'transparent',
|
||||
plotBackgroundColor: null,
|
||||
plotBorderWidth: null,
|
||||
plotShadow: false,
|
||||
type: 'pie',
|
||||
},
|
||||
this.chart.setOption({
|
||||
color: ['red', '#e64524', 'orange', '#007CBB', 'grey', 'green'],
|
||||
title: {
|
||||
text: '',
|
||||
},
|
||||
tooltip: {
|
||||
pointFormat: '<b>{point.percentage:.1f}%</b>',
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
showInLegend: true,
|
||||
borderWidth: 0,
|
||||
},
|
||||
formatter: '<b>{b}: {d}%</b>',
|
||||
},
|
||||
legend: {
|
||||
align: 'left',
|
||||
floating: true,
|
||||
symbolRadius: 2,
|
||||
itemStyle: {
|
||||
fontSize: '12px',
|
||||
fontWeight: '100',
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
width: '60%',
|
||||
itemWidth: 12,
|
||||
itemHeight: 12,
|
||||
width: '50%',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
innerSize: '60%',
|
||||
itemStyle: {
|
||||
borderRadius: 3,
|
||||
borderWidth: 1,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
radius: ['50%', '80%'],
|
||||
name: res[severity],
|
||||
type: 'pie',
|
||||
center: ['80%', '50%'],
|
||||
center: ['68%', '50%'],
|
||||
data: [
|
||||
{
|
||||
name: res[c],
|
||||
y: summary?.critical_cnt || 0,
|
||||
color: 'red',
|
||||
value: summary?.critical_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: res[h],
|
||||
y: summary?.high_cnt || 0,
|
||||
color: '#e64524',
|
||||
value: summary?.high_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: res[m],
|
||||
y: summary?.medium_cnt || 0,
|
||||
color: 'orange',
|
||||
value: summary?.medium_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: res[l],
|
||||
y: summary?.low_cnt || 0,
|
||||
color: '#007CBB',
|
||||
value: summary?.low_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: res[u],
|
||||
y: summary?.unknown_cnt || 0,
|
||||
color: 'grey',
|
||||
value: summary?.unknown_cnt || 0,
|
||||
},
|
||||
{
|
||||
name: res[n],
|
||||
y: summary?.none_cnt || 0,
|
||||
color: 'green',
|
||||
value: summary?.none_cnt || 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -185,4 +185,9 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
|
||||
? '#000'
|
||||
: '#fff';
|
||||
}
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onResize(event: any) {
|
||||
this.chart.resize();
|
||||
}
|
||||
}
|
||||
|
@ -76,9 +76,35 @@ import { HarborDatetimePipe } from './pipes/harbor-datetime.pipe';
|
||||
import { RemainingTimeComponent } from './components/remaining-time/remaining-time.component';
|
||||
import { LabelSelectorComponent } from './components/label-selector/label-selector.component';
|
||||
import { ScrollSectionDirective } from './directives/scroll/scroll-section.directive';
|
||||
import { ScrollManagerService } from './directives/scroll/scroll-manager.service';
|
||||
import { ScrollAnchorDirective } from './directives/scroll/scroll-anchor.directive';
|
||||
import { AppLevelAlertsComponent } from './components/app-level-alerts/app-level-alerts.component';
|
||||
// import echarts
|
||||
import * as echarts from 'echarts/core';
|
||||
import { PieChart } from 'echarts/charts';
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
DatasetComponent,
|
||||
TransformComponent,
|
||||
LegendComponent,
|
||||
} from 'echarts/components';
|
||||
import { LabelLayout, UniversalTransition } from 'echarts/features';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
|
||||
// register necessary components
|
||||
echarts.use([
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
DatasetComponent,
|
||||
TransformComponent,
|
||||
PieChart,
|
||||
LabelLayout,
|
||||
UniversalTransition,
|
||||
CanvasRenderer,
|
||||
LegendComponent,
|
||||
]);
|
||||
|
||||
// ClarityIcons is publicly accessible from the browser's window object.
|
||||
declare const ClarityIcons: ClarityIconsApi;
|
||||
|
Loading…
Reference in New Issue
Block a user