From 6509f8f185983b3dd9bce06a87a01a1da12f54c1 Mon Sep 17 00:00:00 2001 From: Savas Vedova <svedova@gitlab.com> Date: Thu, 3 Oct 2024 11:37:18 +0000 Subject: [PATCH] Display page header and subheader Add a page title to the project security dashboard page. EE: true Changelog: added --- .../project/project_security_dashboard.vue | 49 ++++++++++++++----- .../security_dashboard/constants.js | 5 ++ .../project_security_dashboard_spec.js | 21 ++++++-- locale/gitlab.pot | 3 ++ 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/ee/app/assets/javascripts/security_dashboard/components/project/project_security_dashboard.vue b/ee/app/assets/javascripts/security_dashboard/components/project/project_security_dashboard.vue index 3db91c1db0065..03fa8b9fdcc0c 100644 --- a/ee/app/assets/javascripts/security_dashboard/components/project/project_security_dashboard.vue +++ b/ee/app/assets/javascripts/security_dashboard/components/project/project_security_dashboard.vue @@ -1,10 +1,11 @@ <script> -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlSprintf, GlLink } from '@gitlab/ui'; import { GlLineChart } from '@gitlab/ui/dist/charts'; import projectsHistoryQuery from 'ee/security_dashboard/graphql/queries/project_vulnerabilities_by_day_and_count.query.graphql'; import severitiesCountQuery from 'ee/security_dashboard/graphql/queries/vulnerability_severities_count.query.graphql'; import SecurityTrainingPromoBanner from 'ee/security_dashboard/components/project/security_training_promo_banner.vue'; import { PROJECT_LOADING_ERROR_MESSAGE } from 'ee/security_dashboard/helpers'; +import { DOC_PATH_PROJECT_SECURITY_DASHBOARD } from 'ee/security_dashboard/constants'; import { createAlert } from '~/alert'; import { formatDate, getDateInPast } from '~/lib/utils/datetime_utility'; import { s__, __ } from '~/locale'; @@ -26,6 +27,8 @@ export default { SecurityTrainingPromoBanner, GlLoadingIcon, GlLineChart, + GlSprintf, + GlLink, }, props: { projectFullPath: { @@ -158,20 +161,44 @@ export default { }; }, }, + i18n: { + title: s__('SecurityReports|Security dashboard'), + subtitle: s__( + 'SecurityReports|Historical view of open vulnerabilities in the default branch. Excludes vulnerabilities that were resolved or dismissed. %{linkStart}Learn more.%{linkEnd}', + ), + }, + DOC_PATH_PROJECT_SECURITY_DASHBOARD, }; </script> <template> - <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-6" /> - - <div v-else> + <div> <security-training-promo-banner v-if="shouldShowPromoBanner" /> - <gl-line-chart - class="gl-mt-6" - :data="dataSeries" - :option="chartOptions" - responsive - :include-legend-avg-max="false" - /> + + <header class="vulnerability-header gl-my-5 gl-grid"> + <h2 class="header-title gl-my-0"> + {{ $options.i18n.title }} + </h2> + <p class="header-description gl-mb-0" data-testid="security-dashboard-description"> + <gl-sprintf :message="$options.i18n.subtitle"> + <template #link="{ content }"> + <gl-link :href="$options.DOC_PATH_PROJECT_SECURITY_DASHBOARD" target="_blank">{{ + content + }}</gl-link> + </template> + </gl-sprintf> + </p> + </header> + <div> + <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-6" /> + <gl-line-chart + v-else + class="gl-mt-6" + :data="dataSeries" + :option="chartOptions" + responsive + :include-legend-avg-max="false" + /> + </div> </div> </template> diff --git a/ee/app/assets/javascripts/security_dashboard/constants.js b/ee/app/assets/javascripts/security_dashboard/constants.js index 28c606f2a5126..c7e5567e67b31 100644 --- a/ee/app/assets/javascripts/security_dashboard/constants.js +++ b/ee/app/assets/javascripts/security_dashboard/constants.js @@ -26,6 +26,11 @@ export const DOC_PATH_SECURITY_SCANNER_INTEGRATION_RETENTION_PERIOD = helpPagePa { anchor: 'retention-period-for-findings' }, ); +export const DOC_PATH_PROJECT_SECURITY_DASHBOARD = helpPagePath( + 'user/application_security/security_dashboard/index', + { anchor: 'project-security-dashboard' }, +); + export const severityLevels = { CRITICAL: 'critical', HIGH: 'high', diff --git a/ee/spec/frontend/security_dashboard/components/project/project_security_dashboard_spec.js b/ee/spec/frontend/security_dashboard/components/project/project_security_dashboard_spec.js index a2888e1767e52..afb47deb9930c 100644 --- a/ee/spec/frontend/security_dashboard/components/project/project_security_dashboard_spec.js +++ b/ee/spec/frontend/security_dashboard/components/project/project_security_dashboard_spec.js @@ -1,12 +1,12 @@ -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlSprintf, GlLink } from '@gitlab/ui'; import { GlLineChart } from '@gitlab/ui/dist/charts'; -import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import SecurityTrainingPromoBanner from 'ee/security_dashboard/components/project/security_training_promo_banner.vue'; import ProjectSecurityDashboard from 'ee/security_dashboard/components/project/project_security_dashboard.vue'; import projectsHistoryQuery from 'ee/security_dashboard/graphql/queries/project_vulnerabilities_by_day_and_count.query.graphql'; import severitiesCountQuery from 'ee/security_dashboard/graphql/queries/vulnerability_severities_count.query.graphql'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { useFakeDate } from 'helpers/fake_date'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -35,7 +35,7 @@ describe('Project Security Dashboard component', () => { } = {}) => { severitiesCountQueryHandler = jest.fn().mockResolvedValue(severitiesCountQueryData); - wrapper = shallowMount(ProjectSecurityDashboard, { + wrapper = shallowMountExtended(ProjectSecurityDashboard, { apolloProvider: createApolloProvider( [projectsHistoryQuery, jest.fn().mockResolvedValue(historyQueryData)], [severitiesCountQuery, severitiesCountQueryHandler], @@ -44,9 +44,24 @@ describe('Project Security Dashboard component', () => { projectFullPath, shouldShowPromoBanner, }, + stubs: { + GlSprintf, + }, }); }; + it('should display page header and subheader', () => { + createWrapper(); + + expect(wrapper.findByText('Security dashboard').exists()).toBe(true); + expect(wrapper.findByTestId('security-dashboard-description').text()).toBe( + 'Historical view of open vulnerabilities in the default branch. Excludes vulnerabilities that were resolved or dismissed. Learn more.', + ); + expect(wrapper.findComponent(GlLink).attributes('href')).toBe( + '/help/user/application_security/security_dashboard/index#project-security-dashboard', + ); + }); + it('should fetch the latest vulnerability count for "detected" and "confirmed" states', () => { createWrapper(); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 22789b0e2dcc8..5e8d30f12841c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -50378,6 +50378,9 @@ msgstr "" msgid "SecurityReports|Hide dismissed" msgstr "" +msgid "SecurityReports|Historical view of open vulnerabilities in the default branch. Excludes vulnerabilities that were resolved or dismissed. %{linkStart}Learn more.%{linkEnd}" +msgstr "" + msgid "SecurityReports|Image" msgstr "" -- GitLab