Skip to content

Commit fb8978e

Browse files
authored
Merge pull request #52 from xingzhang-suse/main
Added more UI components
2 parents 2f88ba6 + c50faf3 commit fb8978e

File tree

16 files changed

+680
-132
lines changed

16 files changed

+680
-132
lines changed

pkg/sbombastic-image-vulnerability-scanner/components/ImageRiskAssessment.vue

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<template>
22
<div class="chart-area">
33
<div class="title">
4-
Most affected images at risk
4+
{{ t('imageScanner.images.imageBySeverityChart.title') }}
55
</div>
66
<div class="severity-bar-chart">
7-
<SeverityBarChart :severityData="severityData" />
7+
<SeverityBarChart :severityData="severityData" :description="t('imageScanner.images.imageBySeverityChart.subTitle')" />
88
</div>
99
</div>
1010
</template>
@@ -23,17 +23,7 @@
2323
required: true
2424
}
2525
},
26-
data() {
27-
return {
28-
severityData: {
29-
Critical: 1627,
30-
High: 353,
31-
Medium: 246,
32-
Low: 65,
33-
None: 293,
34-
}
35-
};
36-
}
26+
data() {}
3727
}
3828
</script>
3929

@@ -45,7 +35,6 @@
4535
align-items: flex-start;
4636
gap: 12px;
4737
flex: 1 0 0;
48-
border-right: 1px solid #DCDEE7;
4938
.title {
5039
color: #141419;
5140
font-family: Lato;

pkg/sbombastic-image-vulnerability-scanner/components/common/AmountBarBySeverity.vue

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
<template>
2-
<div>
2+
<div v-if="isCollapsed">
3+
<StackedPercentageBar
4+
:percentages="pecentages"
5+
:primaryColors="['#880E1E','#D32F2F','#FB8C00','#FDD835','#E0E0E0','#F4F5FA']"
6+
:height="7"
7+
/>
8+
</div>
9+
<div v-else>
310
<div class="bar">
411
<div class="badge" :class="badgeColor('critical', cveAmount.critical)">{{ cveAmount.critical }}</div>
512
<div class="badge" :class="badgeColor('high', cveAmount.high)">{{ cveAmount.high }}</div>
@@ -11,12 +18,20 @@
1118
</template>
1219

1320
<script>
21+
import StackedPercentageBar from '@sbombastic-image-vulnerability-scanner/components/common/StackedPercentageBar';
1422
export default {
1523
name: 'amountBarBySeverity',
24+
components: {
25+
StackedPercentageBar,
26+
},
1627
props: {
1728
cveAmount: {
1829
type: Object,
1930
default: () => {}
31+
},
32+
isCollapsed: {
33+
type: Boolean,
34+
default: false,
2035
}
2136
},
2237
methods: {
@@ -26,6 +41,18 @@
2641
_class[className] = true;
2742
return _class;
2843
}
44+
},
45+
computed: {
46+
pecentages() {
47+
let total = this.cveAmount.critical + this.cveAmount.high + this.cveAmount.medium + this.cveAmount.low + this.cveAmount.none;
48+
return [
49+
this.cveAmount.critical * 100 / total,
50+
this.cveAmount.high * 100 / total,
51+
this.cveAmount.medium * 100 / total,
52+
this.cveAmount.low * 100 / total,
53+
this.cveAmount.none * 100 / total,
54+
];
55+
}
2956
}
3057
}
3158
</script>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<template>
2+
<div ref="bar" class="bar-container">
3+
<div
4+
v-for="n in totalBlocks"
5+
:key="n"
6+
class="block"
7+
:class="{ filled: n <= filledBlocks }"
8+
></div>
9+
</div>
10+
</template>
11+
12+
<script>
13+
export default {
14+
name: 'blockPercentageBar',
15+
props: {
16+
percentage: {
17+
type: Number,
18+
required: true,
19+
validator: value => value >= 0 && value <= 100,
20+
},
21+
eventHandler: {
22+
type: Function
23+
},
24+
},
25+
data() {
26+
return {
27+
totalBlocks: 0,
28+
filledBlocks: 0,
29+
resizeObserver: null,
30+
}
31+
},
32+
methods: {
33+
calculateBlocks() {
34+
const el = this.$refs.bar
35+
if (!el) return;
36+
const width = el.offsetWidth;
37+
const blockWidth = 4;
38+
const total = Math.floor(width / blockWidth / 2);
39+
this.totalBlocks = total;
40+
this.filledBlocks = Math.round((this.percentage / 100) * total);
41+
},
42+
debounce(func, delay = 300) {
43+
let timeout
44+
return function (...args) {
45+
clearTimeout(timeout)
46+
timeout = setTimeout(() => func.apply(this, args), delay)
47+
}
48+
}
49+
},
50+
watch: {
51+
percentage() {
52+
this.calculateBlocks();
53+
},
54+
},
55+
mounted() {
56+
this.calculateBlocks();
57+
// window.addEventListener('resize', this.debounce(this.calculateBlocks, 500));
58+
this.eventHandler(this.calculateBlocks);
59+
},
60+
onBeforeUnmount() {
61+
// window.removeEventListener('resize', this.debounce(this.calculateBlocks, 500));
62+
},
63+
beforeDestroy() {
64+
// window.removeEventListener('resize', this.debounce(this.calculateBlocks, 500));
65+
},
66+
}
67+
</script>
68+
69+
<style scoped>
70+
.bar-container {
71+
display: grid;
72+
grid-auto-flow: column;
73+
grid-auto-columns: minmax(4px, 1fr);
74+
gap: 3px;
75+
width: 100%;
76+
height: 16px;
77+
}
78+
79+
.block {
80+
background-color: #e0e0e0;
81+
border-radius: 1px;
82+
transition: background-color 0.2s ease;
83+
}
84+
85+
.block.filled {
86+
background-color: #888ca0;
87+
}
88+
</style>

pkg/sbombastic-image-vulnerability-scanner/components/common/ScoreBadge.vue

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@
77

88
<script>
99
export default {
10-
name: 'ScoreBadge',
10+
name: 'scoreBadge',
1111
props: {
12-
score: Number,
13-
scoreType: String
12+
score:{
13+
type: Number,
14+
default: 0
15+
},
16+
scoreType: {
17+
type: String,
18+
default: ""
19+
}
1420
},
1521
computed: {
1622
severity() {

pkg/sbombastic-image-vulnerability-scanner/components/common/SeverityBarChart.vue

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
<div class="severity-bar-chart">
33
<div class="severity-heading">
44
<span class="vul-total">{{ total }}</span>
5-
<span class="vul-desc">vulnerabilities in total</span>
5+
<span class="vul-desc">{{ description }}</span>
66
</div>
77
<div class="severity-chart">
88
<div v-for="(value, key) in severityData" :key="key" class="severity-item">
9-
<div class="severity-item-name">{{ key }}</div>
10-
<PercentageBar class="severity-item-bar" :modelValue="percentage(value)" />
9+
<div class="severity-item-name">{{ t(`imageScanner.enum.severity.${ key }`) }}</div>
10+
<PercentageBar class="severity-item-bar" :colorStops="{0: `--cve-${ key }`}" :value="percentage(value)" :height="7"/>
1111
<div class="severity-item-value"> {{ value }}</div>
1212
</div>
1313
</div>
1414
</div>
1515
</template>
1616

1717
<script>
18-
import PercentageBar from '@shell/components/PercentageBar.vue';
18+
import PercentageBar from '@sbombastic-image-vulnerability-scanner/components/rancher-rewritten/shell/components/PercentageBar';
1919
2020
export default {
2121
name: 'SeverityBarChart',
@@ -26,7 +26,11 @@ export default {
2626
severityData: {
2727
type: Object,
2828
required: true
29-
}
29+
},
30+
description: {
31+
type: String,
32+
required: true
33+
},
3034
},
3135
methods: {
3236
percentage(value) {
@@ -84,10 +88,10 @@ export default {
8488
flex-direction: column;
8589
gap: 4px;
8690
flex: 3;
87-
8891
.severity-item {
8992
display: flex;
9093
align-items: center;
94+
margin: 2px 0;
9195
gap: 12px;
9296
9397
.severity-item-name {
@@ -100,15 +104,22 @@ export default {
100104
flex: 1;
101105
overflow: hidden;
102106
}
107+
103108
.severity-item-value {
104-
width: 30px;
109+
width: 50px;
105110
text-align: right;
106111
align-items: left;
107112
gap: 12px;
108113
}
109-
110-
111114
}
112115
}
116+
117+
118+
--cve-critical: #880E1E;
119+
--cve-high: #DE2136;
120+
--cve-medium: #FF8533;
121+
--cve-low: #EEC707;
122+
--cve-none: #DCDEE7;
123+
--border: #F4F5FA;
113124
}
114125
</style>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<script>
2+
export default {
3+
name: "stackedPercentageBar",
4+
props: {
5+
percentages: {
6+
type: Array,
7+
required: true,
8+
validator(value) {
9+
return value.reduce((curr, sum) => sum + curr) <= 100;
10+
}
11+
},
12+
primaryColors: {
13+
type: Array,
14+
default: ['--primary']
15+
},
16+
secondaryColor: {
17+
type: String,
18+
default: '--border'
19+
},
20+
height: {
21+
type: Number,
22+
default: 15
23+
}
24+
},
25+
computed: {
26+
indicatorStyle() {
27+
return this.percentages.map((percentage, index) => {
28+
return {
29+
width: `${ percentage }%`,
30+
height: `${ this.height }px`,
31+
backgroundColor: this.primaryColors[index]
32+
}
33+
});
34+
},
35+
barStyle() {
36+
return {
37+
backgroundColor: `var(${ this.secondaryColor })`,
38+
height: `${ this.height }px`,
39+
borderRadius: `${ this.height / 2 }px`,
40+
};
41+
},
42+
}
43+
};
44+
</script>
45+
46+
<template>
47+
<div
48+
class="bar"
49+
:style="barStyle"
50+
>
51+
<div v-for="(percentage, index) in percentages"
52+
class="indicator"
53+
:style="indicatorStyle[index]"
54+
/>
55+
</div>
56+
</template>
57+
58+
<style lang="scss" scoped>
59+
.bar {
60+
width: 100%;
61+
overflow: hidden;
62+
position: relative;
63+
64+
.indicator {
65+
height: 100%;
66+
}
67+
}
68+
</style>

0 commit comments

Comments
 (0)