diff --git a/ee/app/assets/javascripts/on_demand_scans_form/components/on_demand_scans_form.vue b/ee/app/assets/javascripts/on_demand_scans_form/components/on_demand_scans_form.vue index cb205acefd9cbeef64bf8dbb355936b03a03a4e8..842ee7fc2f00050bf89b1550054379ea5a4500f1 100644 --- a/ee/app/assets/javascripts/on_demand_scans_form/components/on_demand_scans_form.vue +++ b/ee/app/assets/javascripts/on_demand_scans_form/components/on_demand_scans_form.vue @@ -173,7 +173,12 @@ export default { SITE_PROFILES_QUERY, ), }, - inject: ['projectPath', 'onDemandScansPath'], + inject: [ + 'projectPath', + 'onDemandScansPath', + 'siteProfilesLibraryPath', + 'scannerProfilesLibraryPath', + ], props: { defaultBranch: { type: String, @@ -505,6 +510,8 @@ export default { v-if="glFeatures.dastUiRedesign" :saved-profiles="dastScan" :full-path="projectPath" + :scanner-profiles-library-path="scannerProfilesLibraryPath" + :site-profiles-library-path="siteProfilesLibraryPath" @error="showErrors" @profiles-selected="selectProfiles" /> diff --git a/ee/app/assets/javascripts/security_configuration/dast/components/configuration_form.vue b/ee/app/assets/javascripts/security_configuration/dast/components/configuration_form.vue index 7c1cc274c36710a5028ed3c1ee12ee373d8a02dc..6ff3c730c7df7b746eb4014740deff60e70ee1f0 100644 --- a/ee/app/assets/javascripts/security_configuration/dast/components/configuration_form.vue +++ b/ee/app/assets/javascripts/security_configuration/dast/components/configuration_form.vue @@ -30,7 +30,13 @@ export default { DastProfilesConfigurator, }, mixins: [glFeatureFlagMixin()], - inject: ['gitlabCiYamlEditPath', 'securityConfigurationPath', 'projectPath'], + inject: [ + 'gitlabCiYamlEditPath', + 'securityConfigurationPath', + 'projectPath', + 'siteProfilesLibraryPath', + 'scannerProfilesLibraryPath', + ], i18n: { dastConfigurationHeader: s__('DastConfig|DAST CI/CD configuration'), dastConfigurationDescription: s__( @@ -88,6 +94,8 @@ export default { :configuration-header="$options.i18n.dastConfigurationHeader" class="gl-mb-6" :full-path="projectPath" + :scanner-profiles-library-path="scannerProfilesLibraryPath" + :site-profiles-library-path="siteProfilesLibraryPath" @error="showErrors" @profiles-selected="updateProfiles" > diff --git a/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_configurator/dast_profiles_configurator.vue b/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_configurator/dast_profiles_configurator.vue index ecf3d7ec110a0d92fca6a6ec9c38996ce97018b1..89f4723fa140abd9e8c2857ce3b1465ecefc42c8 100644 --- a/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_configurator/dast_profiles_configurator.vue +++ b/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_configurator/dast_profiles_configurator.vue @@ -92,6 +92,16 @@ export default { required: false, default: '', }, + siteProfilesLibraryPath: { + type: String, + required: false, + default: '', + }, + scannerProfilesLibraryPath: { + type: String, + required: false, + default: '', + }, }, data() { return { @@ -145,6 +155,11 @@ export default { selectedProfiles() { return this.profileType === SCANNER_TYPE ? this.scannerProfiles : this.siteProfiles; }, + libraryLink() { + return this.profileType === SCANNER_TYPE + ? this.scannerProfilesLibraryPath + : this.siteProfilesLibraryPath; + }, }, watch: { selectedScannerProfile: 'updateProfiles', @@ -269,6 +284,7 @@ export default { :profiles="selectedProfiles" :profile-id-in-use="profileIdInUse" :active-profile="activeProfile" + :library-link="libraryLink" :profile-type="profileType" :is-open="isSideDrawerOpen" :is-loading="isLoadingProfiles" diff --git a/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar.vue b/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar.vue index b7591ab750891489861a3447ccd8bf5752f4c613..1418a059b0f80747fc7efeb784b2a2718f338244 100644 --- a/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar.vue +++ b/ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar.vue @@ -1,6 +1,7 @@ <script> import { isEmpty } from 'lodash'; -import { GlDrawer } from '@gitlab/ui'; +import { GlDrawer, GlLink } from '@gitlab/ui'; +import { s__, sprintf } from '~/locale'; import { SCANNER_TYPE, SIDEBAR_VIEW_MODE } from 'ee/on_demand_scans/constants'; import { REFERRAL } from 'ee/security_configuration/dast_profiles/dast_scanner_profiles/constants'; import DastProfilesLoader from 'ee/security_configuration/dast_profiles/components/dast_profiles_loader.vue'; @@ -32,8 +33,12 @@ import DastProfilesSidebarList from './dast_profiles_sidebar_list.vue'; export default { SIDEBAR_VIEW_MODE, + i18n: { + footerLinkText: s__('DastProfiles|Manage %{profileType} profiles'), + }, components: { GlDrawer, + GlLink, DastProfilesLoader, DastProfilesSidebarHeader, DastProfilesSidebarEmptyState, @@ -92,6 +97,11 @@ export default { required: false, default: SIDEBAR_VIEW_MODE.READING_MODE, }, + libraryLink: { + type: String, + required: false, + default: null, + }, }, data() { return { @@ -115,6 +125,11 @@ export default { isEditingMode() { return this.sidebarViewMode === SIDEBAR_VIEW_MODE.EDITING_MODE; }, + footerLinkText() { + return sprintf(this.$options.i18n.footerLinkText, { + profileType: this.profileType, + }); + }, }, /** * Only if activeProfile is passed from parent @@ -231,5 +246,12 @@ export default { /> </template> </template> + <template v-if="libraryLink" #footer> + <div class="gl-w-full gl-text-center"> + <gl-link :href="libraryLink"> + {{ footerLinkText }} + </gl-link> + </div> + </template> </gl-drawer> </template> diff --git a/ee/spec/frontend/security_configuration/dast/components/configuration_form_spec.js b/ee/spec/frontend/security_configuration/dast/components/configuration_form_spec.js index 486709cffa55481aa800c0dac51f3a8305e85c33..77bd433b0c81945a7d721fad59fda865eff97e44 100644 --- a/ee/spec/frontend/security_configuration/dast/components/configuration_form_spec.js +++ b/ee/spec/frontend/security_configuration/dast/components/configuration_form_spec.js @@ -19,6 +19,8 @@ const [siteProfile] = siteProfiles; const securityConfigurationPath = '/security/configuration'; const gitlabCiYamlEditPath = '/ci/editor'; const projectPath = '/project/path'; +const siteProfilesLibraryPath = 'siteProfilesLibraryPath'; +const scannerProfilesLibraryPath = 'scannerProfilesLibraryPath'; const selectedScannerProfileName = 'My Scan profile'; const selectedSiteProfileName = 'My site profile'; @@ -75,6 +77,8 @@ describe('EE - DAST Configuration Form', () => { provide: { securityConfigurationPath, gitlabCiYamlEditPath, + scannerProfilesLibraryPath, + siteProfilesLibraryPath, projectPath, ...glFeatures, }, diff --git a/ee/spec/frontend/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar_spec.js b/ee/spec/frontend/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar_spec.js index 1d2c2dcd50a11d94e39536b018c93fa458f86946..a17ca5fb9d8684b8ef63832a78c98531f724ac86 100644 --- a/ee/spec/frontend/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar_spec.js +++ b/ee/spec/frontend/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar_spec.js @@ -1,5 +1,6 @@ -import { GlDrawer } from '@gitlab/ui'; +import { GlDrawer, GlLink } from '@gitlab/ui'; import { nextTick } from 'vue'; +import { __ } from '~/locale'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import DastProfilesSidebar from 'ee/security_configuration/dast_profiles/dast_profiles_sidebar/dast_profiles_sidebar.vue'; import DastProfilesLoader from 'ee/security_configuration/dast_profiles/components/dast_profiles_loader.vue'; @@ -27,6 +28,7 @@ describe('DastProfilesSidebar', () => { const findSidebarHeader = () => wrapper.findByTestId('sidebar-header'); const findEmptyStateHeader = () => wrapper.findByTestId('empty-state-header'); const findNewScanButton = () => wrapper.findByTestId('new-profile-button'); + const findFooterLink = () => wrapper.findComponent(GlLink); const findEmptyNewScanButton = () => wrapper.findByTestId('new-empty-profile-button'); const findNewDastScannerProfileForm = () => wrapper.findByTestId('dast-scanner-parent-group'); const findCancelButton = () => wrapper.findByTestId('dast-profile-form-cancel-button'); @@ -130,4 +132,16 @@ describe('DastProfilesSidebar', () => { expect(findGlDrawer().props('headerSticky')).toEqual(true); }); }); + + describe.each` + profileType | expectedResult + ${SCANNER_TYPE} | ${__(`Manage ${SCANNER_TYPE} profiles`)} + ${SITE_TYPE} | ${__(`Manage ${SITE_TYPE} profiles`)} + `('sticky footer', ({ profileType, expectedResult }) => { + const libraryLink = 'libraryLink'; + createComponent({ profileType, libraryLink }); + + expect(findFooterLink().text()).toBe(expectedResult); + expect(findFooterLink().attributes('href')).toEqual(libraryLink); + }); });