From 730de9777ed1782beb7fa48cbab17e00f6ce3a19 Mon Sep 17 00:00:00 2001 From: Fernando Arias <farias@gitlab.com> Date: Tue, 17 May 2022 18:05:38 +0000 Subject: [PATCH] Add license compliance links * Add link to manage policies * Add link to see full report --- .../components/extensions/base.vue | 2 +- .../extensions/license_compliance/index.js | 14 ++++ .../stores/mr_widget_store.js | 2 + .../license_compliance/index_spec.js | 75 ++++++++++++++----- locale/gitlab.pot | 6 ++ 5 files changed, 80 insertions(+), 19 deletions(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue index bbe15f659f5f6..0bc17de638b73 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue @@ -254,7 +254,7 @@ export default { class="media-body gl-display-flex gl-flex-direction-row! gl-align-self-center" data-testid="widget-extension-top-level" > - <div class="gl-flex-grow-1"> + <div class="gl-flex-grow-1" data-testid="widget-extension-top-level-summary"> <template v-if="isLoadingSummary">{{ widgetLoadingText }}</template> <template v-else-if="hasFetchError">{{ widgetErrorText }}</template> <div v-else> diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/extensions/license_compliance/index.js b/ee/app/assets/javascripts/vue_merge_request_widget/extensions/license_compliance/index.js index 396cdbfcef1e8..6046f503adbbd 100644 --- a/ee/app/assets/javascripts/vue_merge_request_widget/extensions/license_compliance/index.js +++ b/ee/app/assets/javascripts/vue_merge_request_widget/extensions/license_compliance/index.js @@ -43,6 +43,20 @@ export default { hasDeniedLicense() { return this.deniedLicenses() > 0; }, + tertiaryButtons() { + return [ + { + text: s__('ciReport|Manage Licenses'), + href: this.licenseCompliance.license_scanning.settings_path, + target: '_blank', + }, + { + text: s__('ciReport|Full Report'), + href: this.licenseCompliance.license_scanning.full_report_path, + target: '_blank', + }, + ]; + }, summary() { if (this.hasReportItems()) { if (this.hasBaseReportLicenses()) { diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index a859b4d48a654..71f04099c00ae 100644 --- a/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -125,11 +125,13 @@ export default class MergeRequestStore extends CEMergeRequestStore { license_scanning_comparison_path, license_scanning_comparison_collapsed_path, api_approvals_path, + license_scanning, }) { this.licenseCompliance = { license_scanning_comparison_path, license_scanning_comparison_collapsed_path, api_approvals_path, + license_scanning, }; } diff --git a/ee/spec/frontend/vue_mr_widget/extensions/license_compliance/index_spec.js b/ee/spec/frontend/vue_mr_widget/extensions/license_compliance/index_spec.js index a4af0c9685d75..0264bd6226054 100644 --- a/ee/spec/frontend/vue_mr_widget/extensions/license_compliance/index_spec.js +++ b/ee/spec/frontend/vue_mr_widget/extensions/license_compliance/index_spec.js @@ -4,6 +4,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import axios from '~/lib/utils/axios_utils'; import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container'; import { registerExtension } from '~/vue_merge_request_widget/components/extensions'; +import actions from '~/vue_merge_request_widget/components/extensions/actions.vue'; import licenseComplianceExtension from 'ee/vue_merge_request_widget/extensions/license_compliance'; import httpStatusCodes from '~/lib/utils/http_status'; import { @@ -20,23 +21,38 @@ describe('License Compliance extension', () => { registerExtension(licenseComplianceExtension); - const endpoint = '/group-name/project-name/-/merge_requests/78/license_scanning_reports'; + const licenseComparisonPath = + '/group-name/project-name/-/merge_requests/78/license_scanning_reports'; + const licenseComparisonPathCollapsed = + '/group-name/project-name/-/merge_requests/78/license_scanning_reports_collapsed'; + const fullReportPath = '/group-name/project-name/-/merge_requests/78/full_report'; + const settingsPath = '/group-name/project-name/-/licenses#licenses'; + const apiApprovalsPath = '/group-name/project-name/-/licenses#policies'; - const mockApi = (statusCode, data) => { + const mockApi = (endpoint, statusCode, data) => { mock.onGet(endpoint).reply(statusCode, data); }; const findToggleCollapsedButton = () => wrapper.findByTestId('toggle-button'); const findAllExtensionListItems = () => wrapper.findAllByTestId('extension-list-item'); + const findActionButtons = () => wrapper.findComponent(actions); + const findByHrefAttribute = (href) => wrapper.find(`[href="${href}"]`); + const findLicenseScanningReport = () => findByHrefAttribute(settingsPath); + const findFullReport = () => findByHrefAttribute(fullReportPath); + const findSummary = () => wrapper.findByTestId('widget-extension-top-level-summary'); const createComponent = () => { wrapper = mountExtended(extensionsContainer, { propsData: { mr: { licenseCompliance: { - license_scanning_comparison_path: endpoint, - license_scanning_comparison_collapsed_path: endpoint, - api_approvals_path: endpoint, + license_scanning_comparison_path: licenseComparisonPath, + license_scanning_comparison_collapsed_path: licenseComparisonPathCollapsed, + api_approvals_path: apiApprovalsPath, + license_scanning: { + settings_path: settingsPath, + full_report_path: fullReportPath, + }, }, }, }, @@ -54,75 +70,98 @@ describe('License Compliance extension', () => { describe('summary', () => { it('displays loading text', () => { - mockApi(httpStatusCodes.OK, licenseComplianceSuccess); + mockApi(licenseComparisonPathCollapsed, httpStatusCodes.OK, licenseComplianceSuccess); createComponent(); - expect(wrapper.text()).toBe('License Compliance test metrics results are being parsed'); + expect(findSummary().text()).toBe('License Compliance test metrics results are being parsed'); }); it('displays failed loading text', async () => { - mockApi(httpStatusCodes.INTERNAL_SERVER_ERROR); + mockApi(licenseComparisonPathCollapsed, httpStatusCodes.INTERNAL_SERVER_ERROR); createComponent(); await waitForPromises(); - expect(wrapper.text()).toBe('License Compliance failed loading results'); + expect(findSummary().text()).toBe('License Compliance failed loading results'); }); it('displays no licenses', async () => { - mockApi(httpStatusCodes.OK, licenseComplianceEmpty); + mockApi(licenseComparisonPathCollapsed, httpStatusCodes.OK, licenseComplianceEmpty); createComponent(); await waitForPromises(); - expect(wrapper.text()).toBe( + expect(findSummary().text()).toBe( 'License Compliance detected no licenses for the source branch only', ); }); it('displays new licenses count', async () => { - mockApi(httpStatusCodes.OK, licenseComplianceSuccess); + mockApi(licenseComparisonPathCollapsed, httpStatusCodes.OK, licenseComplianceSuccess); createComponent(); await waitForPromises(); - expect(wrapper.text()).toBe( + expect(findSummary().text()).toBe( 'License Compliance detected 3 licenses for the source branch only', ); }); it('displays removed licenses count', async () => { - mockApi(httpStatusCodes.OK, licenseComplianceRemovedLicenses); + mockApi(licenseComparisonPathCollapsed, httpStatusCodes.OK, licenseComplianceRemovedLicenses); createComponent(); await waitForPromises(); - expect(wrapper.text()).toBe( + expect(findSummary().text()).toBe( 'License Compliance detected no licenses for the source branch only', ); }); it('displays new and removed licenses count', async () => { - mockApi(httpStatusCodes.OK, licenseComplianceNewAndRemovedLicenses); + mockApi( + licenseComparisonPathCollapsed, + httpStatusCodes.OK, + licenseComplianceNewAndRemovedLicenses, + ); createComponent(); await waitForPromises(); - expect(wrapper.text()).toBe( + expect(findSummary().text()).toBe( 'License Compliance detected 3 licenses for the source branch only', ); }); }); + describe('actions buttons', () => { + it('displays manage licenses and full report links', async () => { + mockApi(licenseComparisonPathCollapsed, httpStatusCodes.OK, licenseComplianceSuccess); + + createComponent(); + + await waitForPromises(); + + expect(findLicenseScanningReport().exists()).toBe(true); + expect(findLicenseScanningReport().text()).toBe('Manage Licenses'); + + expect(findFullReport().exists()).toBe(true); + expect(findFullReport().text()).toBe('Full Report'); + + expect(findActionButtons().exists()).toBe(true); + }); + }); + describe('expanded data', () => { describe('with new licenses', () => { beforeEach(async () => { - mockApi(httpStatusCodes.OK, licenseComplianceSuccessExpanded); + mockApi(licenseComparisonPathCollapsed, httpStatusCodes.OK, licenseComplianceSuccess); + mockApi(licenseComparisonPath, httpStatusCodes.OK, licenseComplianceSuccessExpanded); createComponent(); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 955e66a75c77c..ec2e2a5192aed 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -44417,6 +44417,9 @@ msgstr "" msgid "ciReport|Found %{issuesWithCount}" msgstr "" +msgid "ciReport|Full Report" +msgstr "" + msgid "ciReport|IaC Scanning" msgstr "" @@ -44455,6 +44458,9 @@ msgstr "" msgid "ciReport|Loading Code Quality report" msgstr "" +msgid "ciReport|Manage Licenses" +msgstr "" + msgid "ciReport|Manage licenses" msgstr "" -- GitLab