Commit bdceb76c authored by Daniel Tian's avatar Daniel Tian Committed by Savas Vedova

Fix security dashboard showing wrong count for more than 100 projects

Changelog: fixed
MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78074
EE: true
parent 9a6ef53c
<script> <script>
import { GlLink, GlTooltipDirective, GlIcon, GlLoadingIcon } from '@gitlab/ui'; import { GlLink, GlTooltipDirective, GlIcon, GlLoadingIcon } from '@gitlab/ui';
import { keyBy } from 'lodash';
import { import {
severityGroupTypes, severityGroupTypes,
severityLevels, severityLevels,
...@@ -8,6 +9,7 @@ import { ...@@ -8,6 +9,7 @@ import {
SEVERITY_GROUPS, SEVERITY_GROUPS,
} from 'ee/security_dashboard/store/modules/vulnerable_projects/constants'; } from 'ee/security_dashboard/store/modules/vulnerable_projects/constants';
import { Accordion, AccordionItem } from 'ee/vue_shared/components/accordion'; import { Accordion, AccordionItem } from 'ee/vue_shared/components/accordion';
import { s__, n__, sprintf } from '~/locale';
export default { export default {
css: { css: {
...@@ -61,7 +63,16 @@ export default { ...@@ -61,7 +63,16 @@ export default {
}; };
}, },
update(results) { update(results) {
return this.processRawData(results); const { vulnerabilityGrades } = this.groupFullPath
? results.group
: results.instanceSecurityDashboard;
// This will convert the results array into an object where the key is the grade property:
// {
// A: { grade: 'A', count: 1, projects: { nodes: [ ... ] },
// B: { grade: 'B', count: 2, projects: { nodes: [ ... ] }
// }
return keyBy(vulnerabilityGrades, 'grade');
}, },
error() { error() {
this.errorLoadingVulnerabilitiesGrades = true; this.errorLoadingVulnerabilitiesGrades = true;
...@@ -75,6 +86,7 @@ export default { ...@@ -75,6 +86,7 @@ export default {
severityGroups() { severityGroups() {
return SEVERITY_GROUPS.map((group) => ({ return SEVERITY_GROUPS.map((group) => ({
...group, ...group,
count: this.vulnerabilityGrades[group.type]?.count || 0,
projects: this.findProjectsForGroup(group), projects: this.findProjectsForGroup(group),
})); }));
}, },
...@@ -85,7 +97,7 @@ export default { ...@@ -85,7 +97,7 @@ export default {
return []; return [];
} }
return this.vulnerabilityGrades[group.type].map((project) => ({ return this.vulnerabilityGrades[group.type].projects.nodes.map((project) => ({
...project, ...project,
mostSevereVulnerability: this.findMostSevereVulnerabilityForGroup(project, group), mostSevereVulnerability: this.findMostSevereVulnerabilityForGroup(project, group),
})); }));
...@@ -110,16 +122,6 @@ export default { ...@@ -110,16 +122,6 @@ export default {
return mostSevereVulnerability; return mostSevereVulnerability;
}, },
processRawData(results) {
const { vulnerabilityGrades } = this.groupFullPath
? results.group
: results.instanceSecurityDashboard;
return vulnerabilityGrades.reduce((acc, v) => {
acc[v.grade] = v.projects.nodes;
return acc;
}, {});
},
shouldAccordionItemBeDisabled({ projects }) { shouldAccordionItemBeDisabled({ projects }) {
return projects?.length < 1; return projects?.length < 1;
}, },
...@@ -132,6 +134,17 @@ export default { ...@@ -132,6 +134,17 @@ export default {
severityText(severityLevel) { severityText(severityLevel) {
return severityLevelsTranslations[severityLevel]; return severityLevelsTranslations[severityLevel];
}, },
getProjectCountString({ count, projects }) {
// The backend only returns the first 100 projects, so if the project count is greater than
// the projects array length, we'll show "100+ projects". Note that n__ only works with
// numbers, so we can't pass it a string like "100+", which is why we need the ternary to
// use a different string for "100+ projects". This is temporary code until this backend issue
// is complete, and we can show the actual counts and page through the projects:
// https://gitlab.com/gitlab-org/gitlab/-/issues/350110
return count > projects.length
? sprintf(s__('SecurityReports|%{count}+ projects'), { count: projects.length })
: n__('%d project', '%d projects', count);
},
}, },
}; };
</script> </script>
...@@ -186,7 +199,7 @@ export default { ...@@ -186,7 +199,7 @@ export default {
{{ severityGroup.type }} {{ severityGroup.type }}
</span> </span>
<span :class="{ 'gl-font-weight-bold': isExpanded, 'gl-text-gray-500': isDisabled }"> <span :class="{ 'gl-font-weight-bold': isExpanded, 'gl-text-gray-500': isDisabled }">
{{ n__('%d project', '%d projects', severityGroup.projects.length) }} {{ getProjectCountString(severityGroup) }}
</span> </span>
</h5> </h5>
</template> </template>
......
...@@ -6,6 +6,7 @@ query groupVulnerabilityGrades($fullPath: ID!) { ...@@ -6,6 +6,7 @@ query groupVulnerabilityGrades($fullPath: ID!) {
id id
vulnerabilityGrades(includeSubgroups: true) { vulnerabilityGrades(includeSubgroups: true) {
grade grade
count
projects { projects {
nodes { nodes {
...Project ...Project
......
...@@ -5,6 +5,7 @@ query instanceVulnerabilityGrades { ...@@ -5,6 +5,7 @@ query instanceVulnerabilityGrades {
instanceSecurityDashboard { instanceSecurityDashboard {
vulnerabilityGrades { vulnerabilityGrades {
grade grade
count
projects { projects {
nodes { nodes {
...Project ...Project
......
...@@ -8,7 +8,6 @@ import { severityGroupTypes } from 'ee/security_dashboard/store/modules/vulnerab ...@@ -8,7 +8,6 @@ import { severityGroupTypes } from 'ee/security_dashboard/store/modules/vulnerab
import { Accordion, AccordionItem } from 'ee/vue_shared/components/accordion'; import { Accordion, AccordionItem } from 'ee/vue_shared/components/accordion';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import { n__ } from '~/locale';
import { import {
mockProjectsWithSeverityCounts, mockProjectsWithSeverityCounts,
mockInstanceVulnerabilityGrades, mockInstanceVulnerabilityGrades,
...@@ -72,7 +71,7 @@ describe('Vulnerability Severity component', () => { ...@@ -72,7 +71,7 @@ describe('Vulnerability Severity component', () => {
'D 1 project', 'D 1 project',
'C 2 projects', 'C 2 projects',
'B 1 project', 'B 1 project',
'A 2 projects', 'A 2+ projects',
]); ]);
}); });
}); });
...@@ -93,7 +92,7 @@ describe('Vulnerability Severity component', () => { ...@@ -93,7 +92,7 @@ describe('Vulnerability Severity component', () => {
'D 1 project', 'D 1 project',
'C 2 projects', 'C 2 projects',
'B 1 project', 'B 1 project',
'A 2 projects', 'A 2+ projects',
]); ]);
}); });
}); });
...@@ -160,10 +159,6 @@ describe('Vulnerability Severity component', () => { ...@@ -160,10 +159,6 @@ describe('Vulnerability Severity component', () => {
}); });
}); });
it('states how many projects are there in the group', () => {
expect(text).toContain(n__('%d project', '%d projects', relatedProjects.length));
});
it('states which levels belong to the group', () => { it('states which levels belong to the group', () => {
expect(text).toContain(`${levels} vulnerabilities present`); expect(text).toContain(`${levels} vulnerabilities present`);
}); });
......
...@@ -73,30 +73,35 @@ const projectsMemoized = mockProjectsWithSeverityCounts(); ...@@ -73,30 +73,35 @@ const projectsMemoized = mockProjectsWithSeverityCounts();
const vulnerabilityGrades = [ const vulnerabilityGrades = [
{ {
grade: 'F', grade: 'F',
count: 1,
projects: { projects: {
nodes: [projectsMemoized[0]], nodes: [projectsMemoized[0]],
}, },
}, },
{ {
grade: 'D', grade: 'D',
count: 1,
projects: { projects: {
nodes: [projectsMemoized[1]], nodes: [projectsMemoized[1]],
}, },
}, },
{ {
grade: 'C', grade: 'C',
count: 2,
projects: { projects: {
nodes: [projectsMemoized[0], projectsMemoized[1]], nodes: [projectsMemoized[0], projectsMemoized[1]],
}, },
}, },
{ {
grade: 'B', grade: 'B',
count: 1,
projects: { projects: {
nodes: [projectsMemoized[1]], nodes: [projectsMemoized[1]],
}, },
}, },
{ {
grade: 'A', grade: 'A',
count: 3,
projects: { projects: {
nodes: [projectsMemoized[2], projectsMemoized[3]], nodes: [projectsMemoized[2], projectsMemoized[3]],
}, },
......
...@@ -31828,6 +31828,9 @@ msgstr "" ...@@ -31828,6 +31828,9 @@ msgstr ""
msgid "SecurityPolicies|Policy type" msgid "SecurityPolicies|Policy type"
msgstr "" msgstr ""
msgid "SecurityReports|%{count}+ projects"
msgstr ""
msgid "SecurityReports|%{firstProject} and %{secondProject}" msgid "SecurityReports|%{firstProject} and %{secondProject}"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment