From 2d105d5ec581388380694a9aec00672f4834c5a6 Mon Sep 17 00:00:00 2001
From: Sascha Eggenberger <seggenberger@gitlab.com>
Date: Wed, 9 Oct 2024 14:27:18 +0200
Subject: [PATCH] Secure policies: Update header to use shared component

---
 .../components/policies/list_header.vue       | 60 +++++++++----------
 .../security/policies/index.html.haml         |  4 +-
 .../components/policies/list_header_spec.js   | 12 ++--
 3 files changed, 39 insertions(+), 37 deletions(-)

diff --git a/ee/app/assets/javascripts/security_orchestration/components/policies/list_header.vue b/ee/app/assets/javascripts/security_orchestration/components/policies/list_header.vue
index d92dda393665a7d9..49f31aadf97f06ba 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policies/list_header.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policies/list_header.vue
@@ -2,6 +2,7 @@
 import { GlAlert, GlButton, GlIcon, GlSprintf } from '@gitlab/ui';
 import { joinPaths } from '~/lib/utils/url_utility';
 import { s__ } from '~/locale';
+import PageHeading from '~/vue_shared/components/page_heading.vue';
 import { NAMESPACE_TYPES } from 'ee/security_orchestration/constants';
 import { NEW_POLICY_BUTTON_TEXT } from '../constants';
 import InvalidPoliciesBanner from './banners/invalid_policies_banner.vue';
@@ -20,6 +21,7 @@ export default {
     GlSprintf,
     InvalidPoliciesBanner,
     ProjectModal,
+    PageHeading,
   },
   inject: [
     'assignedPolicyProject',
@@ -112,31 +114,28 @@ export default {
     >
       {{ alertText }}
     </gl-alert>
-    <header class="gl-my-6 gl-flex gl-flex-col">
-      <div class="gl-flex gl-items-start">
-        <div class="gl-my-0 gl-grow">
-          <h2 class="gl-mt-0">
-            {{ $options.i18n.title }}
-          </h2>
-          <p data-testid="policies-subheader">
-            <gl-sprintf :message="$options.i18n.subtitle[namespaceType]">
-              <template #link="{ content }">
-                <gl-button
-                  class="!gl-pb-1"
-                  variant="link"
-                  :href="documentationPath"
-                  target="_blank"
-                >
-                  {{ content }}
-                </gl-button>
-              </template>
-            </gl-sprintf>
-          </p>
-        </div>
+
+    <page-heading :heading="$options.i18n.title">
+      <template #description>
+        <gl-sprintf :message="$options.i18n.subtitle[namespaceType]">
+          <template #link="{ content }">
+            <gl-button
+              class="!gl-pb-1"
+              variant="link"
+              :href="documentationPath"
+              target="_blank"
+              data-testid="more-information-link"
+            >
+              {{ content }}
+            </gl-button>
+          </template>
+        </gl-sprintf>
+      </template>
+
+      <template #actions>
         <gl-button
           v-if="!disableSecurityPolicyProject"
           data-testid="edit-project-policy-button"
-          class="gl-mr-4"
           :loading="projectIsBeingLinked"
           @click="showNewPolicyModal"
         >
@@ -145,7 +144,6 @@ export default {
         <gl-button
           v-else-if="hasAssignedPolicyProject"
           data-testid="view-project-policy-button"
-          class="gl-mr-3"
           target="_blank"
           :href="securityPolicyProjectPath"
         >
@@ -160,15 +158,15 @@ export default {
         >
           {{ $options.i18n.newPolicyButtonText }}
         </gl-button>
-      </div>
+      </template>
+    </page-heading>
 
-      <project-modal
-        :visible="modalVisible"
-        @close="modalVisible = false"
-        @project-updated="updateAlertText"
-        @updating-project="isUpdatingProject"
-      />
-    </header>
+    <project-modal
+      :visible="modalVisible"
+      @close="modalVisible = false"
+      @project-updated="updateAlertText"
+      @updating-project="isUpdatingProject"
+    />
 
     <!-- <breaking-changes-banner class="gl-mt-3 gl-mb-6" /> -->
     <deprecated-custom-scan-banner v-if="hasDeprecatedCustomScanPolicies" class="gl-mb-6 gl-mt-3" />
diff --git a/ee/app/views/projects/security/policies/index.html.haml b/ee/app/views/projects/security/policies/index.html.haml
index 0831cbbe0dbe752d..8a02678637744ff7 100644
--- a/ee/app/views/projects/security/policies/index.html.haml
+++ b/ee/app/views/projects/security/policies/index.html.haml
@@ -1,4 +1,6 @@
-- breadcrumb_title _("Policies")
+- title = _("Policies")
+- page_title title
+- breadcrumb_title title
 - @content_wrapper_class = 'js-security-policies-container-wrapper'
 - disable_security_policy_project = !can_update_security_orchestration_policy_project?(project)
 - disable_scan_policy_update = !can_modify_security_policy?(project)
diff --git a/ee/spec/frontend/security_orchestration/components/policies/list_header_spec.js b/ee/spec/frontend/security_orchestration/components/policies/list_header_spec.js
index 87b99e2c69a47691..a6130402f9d397ec 100644
--- a/ee/spec/frontend/security_orchestration/components/policies/list_header_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policies/list_header_spec.js
@@ -1,5 +1,6 @@
 import { GlButton, GlSprintf } from '@gitlab/ui';
 import { nextTick } from 'vue';
+import PageHeading from '~/vue_shared/components/page_heading.vue';
 import BreakingChangesBanner from 'ee/security_orchestration/components/policies/banners/breaking_changes_banner.vue';
 import DeprecatedCustomScanBanner from 'ee/security_orchestration/components/policies/banners/deprecated_custom_scan_banner.vue';
 import ExceedingActionsBanner from 'ee/security_orchestration/components/policies/banners/exceeding_actions_banner.vue';
@@ -20,11 +21,11 @@ describe('List Header Component', () => {
   const findErrorAlert = () => wrapper.findByTestId('error-alert');
   const findScanNewPolicyModal = () => wrapper.findComponent(ProjectModal);
   const findHeader = () => wrapper.findByRole('heading');
-  const findMoreInformationLink = () => wrapper.findComponent(GlButton);
+  const findMoreInformationLink = () => wrapper.findByTestId('more-information-link');
   const findEditPolicyProjectButton = () => wrapper.findByTestId('edit-project-policy-button');
   const findViewPolicyProjectButton = () => wrapper.findByTestId('view-project-policy-button');
   const findNewPolicyButton = () => wrapper.findByTestId('new-policy-button');
-  const findSubheader = () => wrapper.findByTestId('policies-subheader');
+  const findPageDescription = () => wrapper.findByTestId('page-heading-description');
   const findBreakingChangesBanner = () => wrapper.findComponent(BreakingChangesBanner);
   const findInvalidPoliciesBanner = () => wrapper.findComponent(InvalidPoliciesBanner);
   const findExceedingActionsBanner = () => wrapper.findComponent(ExceedingActionsBanner);
@@ -58,6 +59,7 @@ describe('List Header Component', () => {
       stubs: {
         GlButton,
         GlSprintf,
+        PageHeading,
       },
     });
   };
@@ -119,14 +121,14 @@ describe('List Header Component', () => {
     });
   });
 
-  describe('subheader', () => {
+  describe('description', () => {
     it.each`
       namespaceType              | expectedText
       ${NAMESPACE_TYPES.GROUP}   | ${'Enforce security policies for this group.'}
       ${NAMESPACE_TYPES.PROJECT} | ${'Enforce security policies for this project.'}
-    `('displays the subheader for $namespaceType', ({ namespaceType, expectedText }) => {
+    `('displays the desciption for $namespaceType', ({ namespaceType, expectedText }) => {
       createWrapper({ provide: { namespaceType } });
-      expect(findSubheader().text()).toMatchInterpolatedText(expectedText);
+      expect(findPageDescription().text()).toMatchInterpolatedText(expectedText);
       expect(findMoreInformationLink().attributes('href')).toBe(documentationPath);
     });
   });
-- 
GitLab