266266 <SortableTable
267267 v-if =" safeTableData && safeTableData.length > 0"
268268 :key =" `table-${isGrouped ? 'grouped' : 'ungrouped'}`"
269- :rows =" safeTableData"
269+ :rows =" isGrouped ? layerData : safeTableData"
270270 :headers =" isGrouped ? LAYER_BASED_TABLE : VULNERABILITY_DETAILS_TABLE"
271271 :has-advanced-filtering =" false"
272272 :namespaced =" false"
@@ -365,6 +365,7 @@ export default {
365365 loadedSbom: null ,
366366 // Cache filtered results to prevent selection issues
367367 cachedFilteredVulnerabilities: [],
368+ layerData: [],
368369 // Download dropdown state
369370 showDownloadDropdown: false ,
370371 filters: {
@@ -433,8 +434,7 @@ export default {
433434 const metadata = this .currentImage .imageMetadata ;
434435
435436 if (metadata? .registryURI && metadata? .repository && metadata? .tag ) {
436- // return `${metadata.registryURI}/${metadata.repository}:${metadata.tag}`;
437- return ` ${ metadata .repository .split (' /' )[0 ] } :${ metadata .tag } ` ;
437+ return ` ${ metadata .registryURI } /${ metadata .repository } :${ metadata .tag } ` ;
438438 }
439439
440440 // Fallback to the hash ID if metadata is not available
@@ -669,7 +669,8 @@ export default {
669669 // Safe data for SortableTable
670670 safeTableData() {
671671 if (this.isGrouped) {
672- const layerData = this.vulnerabilitiesByLayer || [];
672+ this.layerData = this.vulnerabilitiesByLayer(this.cachedFilteredVulnerabilities) || [];
673+ const layerData = this.vulnerabilitiesByLayer(this.cachedFilteredVulnerabilities) || [];
673674
674675 return layerData.filter((item) => item && typeof item === 'object' && item.id);
675676 } else {
@@ -684,82 +685,6 @@ export default {
684685 return this.selectedVulnerabilities ? this.selectedVulnerabilities.length : 0;
685686 },
686687
687- // Group vulnerabilities by layer (diffID) - following ImageOverview pattern
688- vulnerabilitiesByLayer() {
689- if (!this.vulnerabilityDetails || !Array.isArray(this.vulnerabilityDetails) || this.vulnerabilityDetails.length === 0) {
690- return [];
691- }
692-
693- try {
694- // Group vulnerabilities by diffID (layer identifier)
695- const layerMap = new Map();
696-
697- this.vulnerabilityDetails.forEach((vuln) => {
698- if (!vuln || typeof vuln !== 'object') {
699- return; // Skip invalid vulnerabilities
700- }
701-
702- const layerId = vuln.diffID || vuln.packagePath || this.t('imageScanner.general.unknown');
703- const mapKey = layerId;
704-
705- if (layerMap.has(mapKey)) {
706- const layer = layerMap.get(mapKey);
707-
708- if (layer && layer.vulnerabilities && Array.isArray(layer.vulnerabilities)) {
709- layer.vulnerabilities.push(vuln);
710- // Count severity
711- const severity = vuln.severity?.toLowerCase() || 'none';
712-
713- if (layer.severityCounts && layer.severityCounts[severity] !== undefined) {
714- layer.severityCounts[severity]++;
715- }
716- }
717- } else {
718- const severityCounts = {
719- critical: 0, high: 0, medium: 0, low: 0, none: 0
720- };
721- const severity = vuln.severity?.toLowerCase() || 'none';
722-
723- if (severityCounts[severity] !== undefined) {
724- severityCounts[severity]++;
725- }
726-
727- layerMap.set(mapKey, {
728- id: mapKey,
729- layerId: this.decodeLayerId(layerId), // Decode layer ID to show meaningful information
730- vulnerabilities: this.formatVulnerabilityCounts(severityCounts),
731- updated: this.getLayerUpdatedTime(layerId),
732- size: this.getLayerSize(layerId),
733- severityCounts,
734- vulnerabilityList: [vuln]
735- });
736- }
737- });
738-
739- // Create severity breakdown and sort
740- const result = Array.from(layerMap.values()).map((layer) => {
741- if (!layer || !layer.severityCounts || !layer.vulnerabilityList || !Array.isArray(layer.vulnerabilityList)) {
742- return null;
743- }
744-
745- const counts = layer.severityCounts;
746-
747- layer.vulnerabilities = this.formatVulnerabilityCounts(counts);
748- layer.updated = this.getLayerUpdatedTime(layer.id);
749- layer.size = this.getLayerSize(layer.id);
750-
751- return layer;
752- }).filter((layer) => layer !== null && layer !== undefined).sort((a, b) => {
753- if (!a || !b) return 0;
754-
755- return (b.vulnerabilityList?.length || 0) - (a.vulnerabilityList?.length || 0);
756- });
757-
758- return result;
759- } catch (error) {
760- return [];
761- }
762- },
763688 },
764689
765690 watch: {
@@ -1381,7 +1306,80 @@ export default {
13811306 link.click();
13821307 document.body.removeChild(link);
13831308 }
1384- }
1309+ },
1310+
1311+ // Group vulnerabilities by layer (diffID) - following ImageOverview pattern
1312+ vulnerabilitiesByLayer(vulnerabilityReport) {
1313+ try {
1314+ // Group vulnerabilities by diffID (layer identifier)
1315+ const layerMap = new Map();
1316+
1317+ vulnerabilityReport.forEach((vuln) => {
1318+ if (!vuln || typeof vuln !== 'object') {
1319+ return; // Skip invalid vulnerabilities
1320+ }
1321+
1322+ const layerId = vuln.diffID || vuln.packagePath || this.t('imageScanner.general.unknown');
1323+ const mapKey = layerId;
1324+
1325+ if (layerMap.has(mapKey)) {
1326+ const layer = layerMap.get(mapKey);
1327+
1328+ if (layer && layer.vulnerabilities && Array.isArray(layer.vulnerabilities)) {
1329+ layer.vulnerabilities.push(vuln);
1330+ // Count severity
1331+ const severity = vuln.severity?.toLowerCase() || 'none';
1332+
1333+ if (layer.severityCounts && layer.severityCounts[severity] !== undefined) {
1334+ layer.severityCounts[severity]++;
1335+ }
1336+ }
1337+ } else {
1338+ const severityCounts = {
1339+ critical: 0, high: 0, medium: 0, low: 0, none: 0
1340+ };
1341+ const severity = vuln.severity?.toLowerCase() || 'none';
1342+
1343+ if (severityCounts[severity] !== undefined) {
1344+ severityCounts[severity]++;
1345+ }
1346+
1347+ layerMap.set(mapKey, {
1348+ id: mapKey,
1349+ layerId: this.decodeLayerId(layerId), // Decode layer ID to show meaningful information
1350+ vulnerabilities: this.formatVulnerabilityCounts(severityCounts),
1351+ updated: this.getLayerUpdatedTime(layerId),
1352+ size: this.getLayerSize(layerId),
1353+ severityCounts,
1354+ vulnerabilityList: [vuln]
1355+ });
1356+ }
1357+ });
1358+
1359+ // Create severity breakdown and sort
1360+ const result = Array.from(layerMap.values()).map((layer) => {
1361+ if (!layer || !layer.severityCounts || !layer.vulnerabilityList || !Array.isArray(layer.vulnerabilityList)) {
1362+ return null;
1363+ }
1364+
1365+ const counts = layer.severityCounts;
1366+
1367+ layer.vulnerabilities = this.formatVulnerabilityCounts(counts);
1368+ layer.updated = this.getLayerUpdatedTime(layer.id);
1369+ layer.size = this.getLayerSize(layer.id);
1370+
1371+ return layer;
1372+ }).filter((layer) => layer !== null && layer !== undefined).sort((a, b) => {
1373+ if (!a || !b) return 0;
1374+
1375+ return (b.vulnerabilityList?.length || 0) - (a.vulnerabilityList?.length || 0);
1376+ });
1377+
1378+ return result;
1379+ } catch (error) {
1380+ return [];
1381+ }
1382+ },
13851383 },
13861384};
13871385</script>
0 commit comments