From 4143aa47931eadd3796978f08fd65f334e4e108a Mon Sep 17 00:00:00 2001
From: Kushal Pandya <kushalspandya@gmail.com>
Date: Wed, 9 Feb 2022 18:32:32 +0530
Subject: [PATCH] Use copy based on issuableType

Update copy usages throughout the app to
determine correct text based on issuableType.
---
 .../components/add_issuable_form.vue          | 12 ++++++--
 .../components/related_issues_block.vue       | 19 ++++++++++--
 .../javascripts/related_issues/constants.js   | 25 ++++++++++++++++
 .../javascripts/related_issues/index.js       |  1 +
 locale/gitlab.pot                             | 15 ++++++++++
 .../components/add_issuable_form_spec.js      | 25 ++++++++++++++++
 .../components/related_issues_block_spec.js   | 29 ++++++++++++++++---
 7 files changed, 117 insertions(+), 9 deletions(-)

diff --git a/app/assets/javascripts/related_issues/components/add_issuable_form.vue b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
index f936c03c5d37b..9ee2e7a4ffd69 100644
--- a/app/assets/javascripts/related_issues/components/add_issuable_form.vue
+++ b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
@@ -9,6 +9,8 @@ import {
   linkedIssueTypesMap,
   addRelatedIssueErrorMap,
   addRelatedItemErrorMap,
+  issuablesFormCategoryHeaderTextMap,
+  issuablesFormInputTextMap,
 } from '../constants';
 import RelatedIssuableInput from './related_issuable_input.vue';
 
@@ -134,6 +136,12 @@ export default {
         epics: mergeUrlParams({ confidential_only: true }, this.autoCompleteSources.epics),
       };
     },
+    issuableCategoryHeaderText() {
+      return issuablesFormCategoryHeaderTextMap[this.issuableType];
+    },
+    issuableInputText() {
+      return issuablesFormInputTextMap[this.issuableType];
+    },
   },
   methods: {
     onPendingIssuableRemoveRequest(params) {
@@ -162,7 +170,7 @@ export default {
   <form @submit.prevent="onFormSubmit">
     <template v-if="showCategorizedIssues">
       <gl-form-group
-        :label="__('The current issue')"
+        :label="issuableCategoryHeaderText"
         label-for="linked-issue-type-radio"
         label-class="label-bold"
         class="mb-2"
@@ -175,7 +183,7 @@ export default {
         />
       </gl-form-group>
       <p class="bold">
-        {{ __('the following issue(s)') }}
+        {{ issuableInputText }}
       </p>
     </template>
     <related-issuable-input
diff --git a/app/assets/javascripts/related_issues/components/related_issues_block.vue b/app/assets/javascripts/related_issues/components/related_issues_block.vue
index 94535e1b8c908..bc97fab9ad23b 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_block.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_block.vue
@@ -5,6 +5,9 @@ import {
   issuableQaClassMap,
   linkedIssueTypesMap,
   linkedIssueTypesTextMap,
+  issuablesBlockHeaderTextMap,
+  issuablesBlockHelpTextMap,
+  issuablesBlockAddButtonTextMap,
 } from '../constants';
 import AddIssuableForm from './add_issuable_form.vue';
 import RelatedIssuesList from './related_issues_list.vue';
@@ -105,6 +108,15 @@ export default {
     hasBody() {
       return this.isFormVisible || this.shouldShowTokenBody;
     },
+    headerText() {
+      return issuablesBlockHeaderTextMap[this.issuableType];
+    },
+    helpLinkText() {
+      return issuablesBlockHelpTextMap[this.issuableType];
+    },
+    addIssuableButtonText() {
+      return issuablesBlockAddButtonTextMap[this.issuableType];
+    },
     badgeLabel() {
       return this.isFetching && this.relatedIssues.length === 0 ? '...' : this.relatedIssues.length;
     },
@@ -138,13 +150,14 @@ export default {
             href="#related-issues"
             aria-hidden="true"
           />
-          <slot name="header-text">{{ __('Linked issues') }}</slot>
+          <slot name="header-text">{{ headerText }}</slot>
           <gl-link
             v-if="hasHelpPath"
             :href="helpPath"
             target="_blank"
             class="gl-display-flex gl-align-items-center gl-ml-2 gl-text-gray-500"
-            :aria-label="__('Read more about related issues')"
+            data-testid="help-link"
+            :aria-label="helpLinkText"
           >
             <gl-icon name="question" :size="12" />
           </gl-link>
@@ -160,7 +173,7 @@ export default {
               v-if="canAdmin"
               data-qa-selector="related_issues_plus_button"
               icon="plus"
-              :aria-label="__('Add a related issue')"
+              :aria-label="addIssuableButtonText"
               :class="qaClass"
               @click="$emit('toggleAddRelatedIssuesForm', $event)"
             />
diff --git a/app/assets/javascripts/related_issues/constants.js b/app/assets/javascripts/related_issues/constants.js
index 89eae069a240e..f911468d8f19c 100644
--- a/app/assets/javascripts/related_issues/constants.js
+++ b/app/assets/javascripts/related_issues/constants.js
@@ -104,3 +104,28 @@ export const PathIdSeparator = {
   Epic: '&',
   Issue: '#',
 };
+
+export const issuablesBlockHeaderTextMap = {
+  [issuableTypesMap.ISSUE]: __('Linked issues'),
+  [issuableTypesMap.EPIC]: __('Linked epics'),
+};
+
+export const issuablesBlockHelpTextMap = {
+  [issuableTypesMap.ISSUE]: __('Read more about related issues'),
+  [issuableTypesMap.EPIC]: __('Read more about related epics'),
+};
+
+export const issuablesBlockAddButtonTextMap = {
+  [issuableTypesMap.ISSUE]: __('Add a related issue'),
+  [issuableTypesMap.EPIC]: __('Add a related epic'),
+};
+
+export const issuablesFormCategoryHeaderTextMap = {
+  [issuableTypesMap.ISSUE]: __('The current issue'),
+  [issuableTypesMap.EPIC]: __('The current epic'),
+};
+
+export const issuablesFormInputTextMap = {
+  [issuableTypesMap.ISSUE]: __('the following issue(s)'),
+  [issuableTypesMap.EPIC]: __('the following epic(s)'),
+};
diff --git a/app/assets/javascripts/related_issues/index.js b/app/assets/javascripts/related_issues/index.js
index 0ee99df14550d..bd9845e616b1c 100644
--- a/app/assets/javascripts/related_issues/index.js
+++ b/app/assets/javascripts/related_issues/index.js
@@ -8,6 +8,7 @@ export default function initRelatedIssues() {
     // eslint-disable-next-line no-new
     new Vue({
       el: relatedIssuesRootElement,
+      name: 'RelatedIssuesApp',
       components: {
         relatedIssuesRoot: RelatedIssuesRoot,
       },
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 76ce6fc67c975..d8c71a9eb0422 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2091,6 +2091,9 @@ msgstr ""
 msgid "Add a numbered list"
 msgstr ""
 
+msgid "Add a related epic"
+msgstr ""
+
 msgid "Add a related issue"
 msgstr ""
 
@@ -21755,6 +21758,9 @@ msgstr ""
 msgid "Linked emails (%{email_count})"
 msgstr ""
 
+msgid "Linked epics"
+msgstr ""
+
 msgid "Linked issues"
 msgstr ""
 
@@ -29685,6 +29691,9 @@ msgstr ""
 msgid "Read more about project permissions %{help_link_open}here%{help_link_close}"
 msgstr ""
 
+msgid "Read more about related epics"
+msgstr ""
+
 msgid "Read more about related issues"
 msgstr ""
 
@@ -36091,6 +36100,9 @@ msgstr ""
 msgid "The contents of this group, its subgroups and projects will be permanently removed after %{deletion_adjourned_period} days on %{date}. After this point, your data cannot be recovered."
 msgstr ""
 
+msgid "The current epic"
+msgstr ""
+
 msgid "The current issue"
 msgstr ""
 
@@ -44006,6 +44018,9 @@ msgstr ""
 msgid "the file"
 msgstr ""
 
+msgid "the following epic(s)"
+msgstr ""
+
 msgid "the following issue(s)"
 msgstr ""
 
diff --git a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
index 2ae32e8960518..ce98a16dbb707 100644
--- a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
+++ b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
@@ -1,3 +1,4 @@
+import { GlFormGroup } from '@gitlab/ui';
 import { mount, shallowMount } from '@vue/test-utils';
 import { nextTick } from 'vue';
 import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue';
@@ -153,6 +154,30 @@ describe('AddIssuableForm', () => {
       });
     });
 
+    describe('categorized issuables', () => {
+      it.each`
+        issuableType              | pathIdSeparator          | contextHeader          | contextFooter
+        ${issuableTypesMap.ISSUE} | ${PathIdSeparator.Issue} | ${'The current issue'} | ${'the following issue(s)'}
+        ${issuableTypesMap.EPIC}  | ${PathIdSeparator.Epic}  | ${'The current epic'}  | ${'the following epic(s)'}
+      `(
+        'show header text as "$contextHeader" and footer text as "$contextFooter" issuableType is set to $issuableType',
+        ({ issuableType, contextHeader, contextFooter }) => {
+          wrapper = shallowMount(AddIssuableForm, {
+            propsData: {
+              issuableType,
+              inputValue: '',
+              showCategorizedIssues: true,
+              pathIdSeparator,
+              pendingReferences: [],
+            },
+          });
+
+          expect(wrapper.findComponent(GlFormGroup).attributes('label')).toBe(contextHeader);
+          expect(wrapper.find('p.bold').text()).toContain(contextFooter);
+        },
+      );
+    });
+
     describe('when it is a Linked Issues form', () => {
       beforeEach(() => {
         wrapper = mount(AddIssuableForm, {
diff --git a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js
index 608fec45bbdaf..c7925034eb012 100644
--- a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js
+++ b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js
@@ -7,6 +7,7 @@ import {
 } from 'jest/issuable/components/related_issuable_mock_data';
 import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue';
 import {
+  issuableTypesMap,
   linkedIssueTypesMap,
   linkedIssueTypesTextMap,
   PathIdSeparator,
@@ -29,14 +30,34 @@ describe('RelatedIssuesBlock', () => {
       wrapper = mount(RelatedIssuesBlock, {
         propsData: {
           pathIdSeparator: PathIdSeparator.Issue,
-          issuableType: 'issue',
+          issuableType: issuableTypesMap.ISSUE,
         },
       });
     });
 
-    it('displays "Linked issues" in the header', () => {
-      expect(wrapper.find('.card-title').text()).toContain('Linked issues');
-    });
+    it.each`
+      issuableType | pathIdSeparator          | titleText          | helpLinkText                        | addButtonText
+      ${'issue'}   | ${PathIdSeparator.Issue} | ${'Linked issues'} | ${'Read more about related issues'} | ${'Add a related issue'}
+      ${'epic'}    | ${PathIdSeparator.Epic}  | ${'Linked epics'}  | ${'Read more about related epics'}  | ${'Add a related epic'}
+    `(
+      'displays "$titleText" in the header, "$helpLinkText" aria-label for help link, and "$addButtonText" aria-label for add button when issuableType is set to "$issuableType"',
+      ({ issuableType, pathIdSeparator, titleText, helpLinkText, addButtonText }) => {
+        wrapper = mount(RelatedIssuesBlock, {
+          propsData: {
+            pathIdSeparator,
+            issuableType,
+            canAdmin: true,
+            helpPath: '/help/user/project/issues/related_issues',
+          },
+        });
+
+        expect(wrapper.find('.card-title').text()).toContain(titleText);
+        expect(wrapper.find('[data-testid="help-link"]').attributes('aria-label')).toBe(
+          helpLinkText,
+        );
+        expect(findIssueCountBadgeAddButton().attributes('aria-label')).toBe(addButtonText);
+      },
+    );
 
     it('unable to add new related issues', () => {
       expect(findIssueCountBadgeAddButton().exists()).toBe(false);
-- 
GitLab