Skip to content

Commit c50faf3

Browse files
Created stacked percentage bar for severity based amount under collapsed mode; Created block percentage bar for affacted image column
1 parent dbe326f commit c50faf3

File tree

10 files changed

+413
-99
lines changed

10 files changed

+413
-99
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
align-items: flex-start;
3636
gap: 12px;
3737
flex: 1 0 0;
38-
border-right: 1px solid #DCDEE7;
3938
.title {
4039
color: #141419;
4140
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() {
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>

pkg/sbombastic-image-vulnerability-scanner/config/sbombastic-image-vulnerability-scanner.ts

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,31 @@ export function init($plugin: IPlugin, store: any) {
1212
inStore: "cluster",
1313
});
1414

15-
virtualType({
16-
labelKey: 'imageScanner.registries.title',
17-
name: PAGE.REGISTRIES,
18-
namespaced: false,
19-
route: {
20-
name: `c-cluster-${PRODUCT_NAME}-${PAGE.REGISTRIES}`,
21-
params: {
22-
product: PRODUCT_NAME
23-
},
24-
meta: { pkg: PRODUCT_NAME, product: PRODUCT_NAME }
25-
}
26-
});
27-
28-
virtualType({
29-
labelKey: 'imageScanner.images.title',
30-
name: PAGE.IMAGE_OVERVIEW,
31-
namespaced: false,
32-
route: {
33-
name: `c-cluster-${PRODUCT_NAME}-${PAGE.IMAGE_OVERVIEW}`,
34-
params: {
35-
product: PRODUCT_NAME
36-
},
37-
meta: { pkg: PRODUCT_NAME, product: PRODUCT_NAME }
38-
}
39-
});
15+
virtualType({
16+
labelKey: 'imageScanner.registries.title',
17+
name: PAGE.REGISTRIES,
18+
namespaced: false,
19+
route: {
20+
name: `c-cluster-${PRODUCT_NAME}-${PAGE.REGISTRIES}`,
21+
params: {
22+
product: PRODUCT_NAME
23+
},
24+
meta: { pkg: PRODUCT_NAME, product: PRODUCT_NAME }
25+
}
26+
});
27+
28+
virtualType({
29+
labelKey: 'imageScanner.images.title',
30+
name: PAGE.IMAGE_OVERVIEW,
31+
namespaced: false,
32+
route: {
33+
name: `c-cluster-${PRODUCT_NAME}-${PAGE.IMAGE_OVERVIEW}`,
34+
params: {
35+
product: PRODUCT_NAME
36+
},
37+
meta: { pkg: PRODUCT_NAME, product: PRODUCT_NAME }
38+
}
39+
});
4040

4141
virtualType({
4242
label: store.getters["i18n/t"]("image_scanner.vulnerabilities.title"),
@@ -51,10 +51,24 @@ export function init($plugin: IPlugin, store: any) {
5151
},
5252
});
5353

54+
virtualType({
55+
label: "Components Demo",
56+
name: "demo",
57+
namespaced: false,
58+
route: {
59+
name: `c-cluster-${PRODUCT_NAME}-demo`,
60+
params: {
61+
product: PRODUCT_NAME,
62+
},
63+
meta: { pkg: PRODUCT_NAME, product: PRODUCT_NAME },
64+
},
65+
});
66+
5467
basicType([
5568
PAGE.REGISTRIES,
5669
PAGE.IMAGE_OVERVIEW,
57-
PAGE.VULNERABILITY_OVERVIEW
70+
PAGE.VULNERABILITY_OVERVIEW,
71+
"demo"
5872
]);
5973

6074
}

0 commit comments

Comments
 (0)