diff --git a/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue b/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue index 470121f68d50f13d18849e35cb1c403c17e32e26..6e13dbd0736f5d778eab79a9326f7405990bfc9a 100644 --- a/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue +++ b/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue @@ -5,6 +5,7 @@ import { debounce, escape } from 'lodash'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { isNumeric } from '~/lib/utils/number_utils'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; +import { s__ } from '~/locale'; import SafeHtml from '~/vue_shared/directives/safe_html'; import { isValidURL } from '~/lib/utils/url_utility'; import { highlighter } from 'ee_else_ce/gfm_auto_complete'; @@ -13,12 +14,7 @@ import workItemAncestorsQuery from '../../graphql/work_item_ancestors.query.grap import groupWorkItemsQuery from '../../graphql/group_work_items.query.graphql'; import projectWorkItemsQuery from '../../graphql/project_work_items.query.graphql'; import workItemsByReferencesQuery from '../../graphql/work_items_by_references.query.graphql'; -import { - WORK_ITEMS_TYPE_MAP, - I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER, - I18N_WORK_ITEM_SEARCH_ERROR, - sprintfWorkItem, -} from '../../constants'; +import { WORK_ITEMS_TYPE_MAP, I18N_WORK_ITEM_SEARCH_ERROR, sprintfWorkItem } from '../../constants'; import { formatAncestors, isReference } from '../../utils'; export default { @@ -126,7 +122,7 @@ export default { error: '', textInputAttrs: { class: '!gl-min-w-fit', - 'aria-label': I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER, + 'aria-label': s__('WorkItem|Search existing items, paste URL, or enter reference ID'), }, }; }, @@ -230,9 +226,6 @@ export default { ); }, }, - i18n: { - addInputPlaceholder: I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER, - }, safeHtmlConfig: { ADD_TAGS: ['strong', 'span'] }, }; </script> @@ -246,7 +239,7 @@ export default { v-model="workItemsToAdd" :dropdown-items="availableWorkItems" :loading="isLoading" - :placeholder="$options.i18n.addInputPlaceholder" + :placeholder="s__('WorkItem|Search existing items, paste URL, or enter reference ID')" menu-class="gl-dropdown-menu-wide dropdown-reduced-height !gl-min-h-7" :container-class="tokenSelectorContainerClass" data-testid="work-item-token-select-input" diff --git a/app/assets/javascripts/work_items/components/work_item_award_emoji.vue b/app/assets/javascripts/work_items/components/work_item_award_emoji.vue index d522708aa84a3638a05f5231008ff3ca773d8dbb..a44f869186021f51998848ca2eb57f21666932e7 100644 --- a/app/assets/javascripts/work_items/components/work_item_award_emoji.vue +++ b/app/assets/javascripts/work_items/components/work_item_award_emoji.vue @@ -3,6 +3,7 @@ import { produce } from 'immer'; import * as Sentry from '~/sentry/sentry_browser_wrapper'; import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils'; +import { s__ } from '~/locale'; import AwardsList from '~/vue_shared/components/awards_list.vue'; import { isLoggedIn } from '~/lib/utils/common_utils'; import { TYPENAME_USER } from '~/graphql_shared/constants'; @@ -10,11 +11,7 @@ import { TYPENAME_USER } from '~/graphql_shared/constants'; import { EMOJI_THUMBS_UP, EMOJI_THUMBS_DOWN } from '~/emoji/constants'; import projectWorkItemAwardEmojiQuery from '../graphql/award_emoji.query.graphql'; import updateAwardEmojiMutation from '../graphql/update_award_emoji.mutation.graphql'; -import { - WIDGET_TYPE_AWARD_EMOJI, - DEFAULT_PAGE_SIZE_EMOJIS, - I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR, -} from '../constants'; +import { WIDGET_TYPE_AWARD_EMOJI, DEFAULT_PAGE_SIZE_EMOJIS } from '../constants'; export default { defaultAwards: [EMOJI_THUMBS_UP, EMOJI_THUMBS_DOWN], @@ -102,7 +99,12 @@ export default { } }, error() { - this.$emit('error', I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR); + this.$emit( + 'error', + s__( + 'WorkItem|Something went wrong while fetching work item award emojis. Please try again.', + ), + ); }, }, }, @@ -117,7 +119,12 @@ export default { }, }); } catch { - this.$emit('error', I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR); + this.$emit( + 'error', + s__( + 'WorkItem|Something went wrong while fetching work item award emojis. Please try again.', + ), + ); } }, isEmojiPresentForCurrentUser(name) { diff --git a/app/assets/javascripts/work_items/components/work_item_change_type_modal.vue b/app/assets/javascripts/work_items/components/work_item_change_type_modal.vue index bbf86b40a7b2f6ca9330ccea2ccb0e24b19d7f02..26e6c7ff15af102bc705a3c6639024112b0725e1 100644 --- a/app/assets/javascripts/work_items/components/work_item_change_type_modal.vue +++ b/app/assets/javascripts/work_items/components/work_item_change_type_modal.vue @@ -12,9 +12,6 @@ import { WORK_ITEM_TYPE_ENUM_EPIC, WORK_ITEM_TYPE_VALUE_EPIC, sprintfWorkItem, - I18N_WORK_ITEM_CHANGE_TYPE_PARENT_ERROR, - I18N_WORK_ITEM_CHANGE_TYPE_CHILD_ERROR, - I18N_WORK_ITEM_CHANGE_TYPE_MISSING_FIELDS_ERROR, WORK_ITEM_WIDGETS_NAME_MAP, WIDGET_TYPE_DESIGNS, } from '../constants'; @@ -313,7 +310,9 @@ export default { if (this.hasParent) { this.warningMessage = sprintfWorkItem( - I18N_WORK_ITEM_CHANGE_TYPE_PARENT_ERROR, + s__( + 'WorkItem|Parent item type %{parentWorkItemType} is not supported on %{workItemType}. Remove the parent item to change type.', + ), this.selectedWorkItemType.value === WORK_ITEM_TYPE_ENUM_EPIC ? WORK_ITEM_TYPE_VALUE_EPIC : this.selectedWorkItemType.text, @@ -325,14 +324,19 @@ export default { } if (this.hasChildren) { - this.warningMessage = sprintf(I18N_WORK_ITEM_CHANGE_TYPE_CHILD_ERROR, { - workItemType: capitalizeFirstCharacter( - this.selectedWorkItemType.value === WORK_ITEM_TYPE_ENUM_EPIC - ? WORK_ITEM_TYPE_VALUE_EPIC.toLocaleLowerCase() - : this.selectedWorkItemType.text.toLocaleLowerCase(), + this.warningMessage = sprintf( + s__( + 'WorkItem|%{workItemType} does not support the %{childItemType} child item types. Remove child items to change type.', ), - childItemType: this.allowedChildTypes?.[0]?.name?.toLocaleLowerCase(), - }); + { + workItemType: capitalizeFirstCharacter( + this.selectedWorkItemType.value === WORK_ITEM_TYPE_ENUM_EPIC + ? WORK_ITEM_TYPE_VALUE_EPIC.toLocaleLowerCase() + : this.selectedWorkItemType.text.toLocaleLowerCase(), + ), + childItemType: this.allowedChildTypes?.[0]?.name?.toLocaleLowerCase(), + }, + ); this.changeTypeDisabled = true; return; @@ -341,7 +345,9 @@ export default { // Compare the widget definitions of both types if (this.hasWidgetDifference) { this.warningMessage = sprintfWorkItem( - I18N_WORK_ITEM_CHANGE_TYPE_MISSING_FIELDS_ERROR, + s__( + 'WorkItem|Some fields are not present in %{workItemType}. If you change type now, this information will be lost.', + ), this.selectedWorkItemType.value === WORK_ITEM_TYPE_ENUM_EPIC ? WORK_ITEM_TYPE_VALUE_EPIC : this.selectedWorkItemType.text, diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue index 17fbce2d3d5f381583cda96b8674f333e9f1d99a..677834a5f6204b2e8517b68266fa419d3f1f6ba2 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue @@ -15,8 +15,6 @@ import { getParameterByName, setUrlParams, updateHistory } from '~/lib/utils/url import CrudComponent from '~/vue_shared/components/crud_component.vue'; import { FORM_TYPES, - WIDGET_ICONS, - WORK_ITEM_STATUS_TEXT, TASKS_ANCHOR, DEFAULT_PAGE_SIZE_CHILD_ITEMS, DETAIL_VIEW_QUERY_PARAM_NAME, @@ -283,8 +281,6 @@ export default { createChildOptionLabel: s__('WorkItem|New task'), noChildItemsOpen: s__('WorkItem|No child items are currently open.'), }, - WIDGET_TYPE_TASK_ICON: WIDGET_ICONS.TASK, - WORK_ITEM_STATUS_TEXT, FORM_TYPES, }; </script> @@ -294,7 +290,7 @@ export default { ref="workItemsLinks" :anchor-id="widgetName" :title="$options.i18n.title" - :icon="$options.WIDGET_TYPE_TASK_ICON" + icon="issue-type-task" :count="childrenCountLabel" :is-loading="isLoading && !fetchNextPageInProgress" is-collapsible diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue index 182d926d802dadba89433720fd5db18099eb7211..87cf9c469a43cee2fcbd8457346dc2cb74701604 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue @@ -12,10 +12,7 @@ import { FORM_TYPES, WORK_ITEMS_TYPE_MAP, WORK_ITEM_TYPE_ENUM_TASK, - I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, - I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP, WORK_ITEM_TYPE_VALUE_EPIC, - I18N_MAX_WORK_ITEMS_ERROR_MESSAGE, MAX_WORK_ITEMS, sprintfWorkItem, WIDGET_TYPE_MILESTONE, @@ -197,11 +194,18 @@ export default { return sprintfWorkItem(s__('WorkItem|Add %{workItemType}'), this.childrenTypeName); }, confidentialityCheckboxLabel() { - return sprintfWorkItem(I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, this.childrenTypeName); + return sprintfWorkItem( + s__( + 'WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least the Planner role', + ), + this.childrenTypeName, + ); }, confidentialityCheckboxTooltip() { return sprintfWorkItem( - I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP, + s__( + 'WorkItem|A non-confidential %{workItemType} cannot be assigned to a confidential parent %{parentWorkItemType}.', + ), this.childrenTypeName, this.parentWorkItemType, ); @@ -413,7 +417,6 @@ export default { projectInputPlaceholder: s__('WorkItem|Select a project'), groupInputPlaceholder: s__('WorkItem|Select a group'), titleInputValidationMessage: __('Maximum of 255 characters'), - maxItemsErrorMessage: I18N_MAX_WORK_ITEMS_ERROR_MESSAGE, }, }; </script> @@ -511,7 +514,7 @@ export default { class="gl-mb-2 gl-text-red-500" data-testid="work-items-limit-error" > - {{ $options.i18n.maxItemsErrorMessage }} + {{ s__('WorkItem|Only 10 items can be added at a time.') }} </div> </div> <div class="gl-flex gl-gap-3"> diff --git a/app/assets/javascripts/work_items/components/work_item_relationships/work_item_add_relationship_form.vue b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_add_relationship_form.vue index 7ce7cbd3758b91c128d49d6388dc91e3d27533fa..7d04217aa4a5075620400121660471bdbd1ef7f9 100644 --- a/app/assets/javascripts/work_items/components/work_item_relationships/work_item_add_relationship_form.vue +++ b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_add_relationship_form.vue @@ -10,8 +10,6 @@ import { LINK_ITEM_FORM_HEADER_LABEL, LINKED_ITEM_TYPE_VALUE, MAX_WORK_ITEMS, - I18N_MAX_WORK_ITEMS_ERROR_MESSAGE, - I18N_MAX_WORK_ITEMS_NOTE_LABEL, } from '../../constants'; export default { @@ -175,8 +173,6 @@ export default { addLinkedItemErrorMessage: s__( 'WorkItem|Something went wrong when trying to link a item. Please try again.', ), - maxItemsNoteLabel: I18N_MAX_WORK_ITEMS_NOTE_LABEL, - maxItemsErrorMessage: I18N_MAX_WORK_ITEMS_ERROR_MESSAGE, }, }; </script> @@ -215,10 +211,10 @@ export default { @searching="searchInProgress = $event" /> <div v-if="errorMessage" class="gl-mb-2 gl-text-danger"> - {{ $options.i18n.maxItemsErrorMessage }} + {{ s__('WorkItem|Only 10 items can be added at a time.') }} </div> <div v-if="!errorMessage" data-testid="max-work-item-note" class="gl-text-subtle"> - {{ $options.i18n.maxItemsNoteLabel }} + {{ s__('WorkItem|Add up to 10 items at a time.') }} </div> <div v-if="showWorkItemsToAddInvalidMessage" diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js index 1053f1a5fa6bb02999c54a3b01b8409ef3448481..250225605ced9c96f44ed4a313a071071d711a28 100644 --- a/app/assets/javascripts/work_items/constants.js +++ b/app/assets/javascripts/work_items/constants.js @@ -72,47 +72,12 @@ export const I18N_WORK_ITEM_ERROR_UPDATING = s__( export const I18N_WORK_ITEM_ERROR_DELETING = s__( 'WorkItem|Something went wrong when deleting the %{workItemType}. Please try again.', ); - -export const I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR = s__( - 'WorkItem|Something went wrong while fetching work item award emojis. Please try again.', -); - -export const I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER = s__( - 'WorkItem|Search existing items, paste URL, or enter reference ID', -); export const I18N_WORK_ITEM_SEARCH_ERROR = s__( 'WorkItem|Something went wrong while fetching the %{workItemType}. Please try again.', ); -export const I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL = s__( - 'WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least the Planner role', -); -export const I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP = s__( - 'WorkItem|A non-confidential %{workItemType} cannot be assigned to a confidential parent %{parentWorkItemType}.', -); export const MAX_WORK_ITEMS = 10; -export const I18N_MAX_WORK_ITEMS_ERROR_MESSAGE = sprintf( - s__('WorkItem|Only %{MAX_WORK_ITEMS} items can be added at a time.'), - { MAX_WORK_ITEMS }, -); -export const I18N_MAX_WORK_ITEMS_NOTE_LABEL = sprintf( - s__('WorkItem|Add up to %{MAX_WORK_ITEMS} items at a time.'), - { MAX_WORK_ITEMS }, -); - -export const I18N_WORK_ITEM_CHANGE_TYPE_PARENT_ERROR = s__( - 'WorkItem|Parent item type %{parentWorkItemType} is not supported on %{workItemType}. Remove the parent item to change type.', -); - -export const I18N_WORK_ITEM_CHANGE_TYPE_CHILD_ERROR = s__( - 'WorkItem|%{workItemType} does not support the %{childItemType} child item types. Remove child items to change type.', -); - -export const I18N_WORK_ITEM_CHANGE_TYPE_MISSING_FIELDS_ERROR = s__( - 'WorkItem|Some fields are not present in %{workItemType}. If you change type now, this information will be lost.', -); - export const sprintfWorkItem = (msg, workItemTypeArg, parentWorkItemType = '') => { const workItemType = workItemTypeArg || s__('WorkItem|item'); return capitalizeFirstCharacter( @@ -123,15 +88,6 @@ export const sprintfWorkItem = (msg, workItemTypeArg, parentWorkItemType = '') = ); }; -export const WIDGET_ICONS = { - TASK: 'issue-type-task', -}; - -export const WORK_ITEM_STATUS_TEXT = { - CLOSED: s__('WorkItem|Closed'), - OPEN: s__('WorkItem|Open'), -}; - export const WORK_ITEMS_TYPE_MAP = { [WORK_ITEM_TYPE_ENUM_INCIDENT]: { icon: `issue-type-incident`, diff --git a/locale/gitlab.pot b/locale/gitlab.pot index bd5b9207b78342f011975352405934b60243c31c..3922cbb22e227e70f3437b9b823f30883cd39783 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -66088,7 +66088,7 @@ msgstr "" msgid "WorkItem|Add a to-do item" msgstr "" -msgid "WorkItem|Add up to %{MAX_WORK_ITEMS} items at a time." +msgid "WorkItem|Add up to 10 items at a time." msgstr "" msgid "WorkItem|All activity" @@ -66484,10 +66484,7 @@ msgstr "" msgid "WorkItem|One or more items cannot be shown. If you're using SAML authentication, this could mean your session has expired." msgstr "" -msgid "WorkItem|Only %{MAX_WORK_ITEMS} items can be added at a time." -msgstr "" - -msgid "WorkItem|Open" +msgid "WorkItem|Only 10 items can be added at a time." msgstr "" msgid "WorkItem|Options:" diff --git a/spec/frontend/work_items/components/work_item_award_emoji_spec.js b/spec/frontend/work_items/components/work_item_award_emoji_spec.js index 6a1305eb804666d3b1644f59e701162ac6c9e273..9bf839ca58f3352c7bd73049017cade8b8060122 100644 --- a/spec/frontend/work_items/components/work_item_award_emoji_spec.js +++ b/spec/frontend/work_items/components/work_item_award_emoji_spec.js @@ -10,10 +10,7 @@ import AwardList from '~/vue_shared/components/awards_list.vue'; import WorkItemAwardEmoji from '~/work_items/components/work_item_award_emoji.vue'; import updateAwardEmojiMutation from '~/work_items/graphql/update_award_emoji.mutation.graphql'; import projectWorkItemAwardEmojiQuery from '~/work_items/graphql/award_emoji.query.graphql'; -import { - DEFAULT_PAGE_SIZE_EMOJIS, - I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR, -} from '~/work_items/constants'; +import { DEFAULT_PAGE_SIZE_EMOJIS } from '~/work_items/constants'; import { EMOJI_THUMBS_UP, EMOJI_THUMBS_DOWN } from '~/emoji/constants'; import { @@ -60,7 +57,9 @@ describe('WorkItemAwardEmoji component', () => { ); const awardEmojiQueryFailureHandler = jest .fn() - .mockRejectedValue(new Error(I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR)); + .mockRejectedValue( + new Error('Something went wrong while fetching work item award emojis. Please try again.'), + ); const awardEmojiAddSuccessHandler = jest.fn().mockResolvedValue(getAwardEmojiResponse(true)); const awardEmojiRemoveSuccessHandler = jest.fn().mockResolvedValue(getAwardEmojiResponse(false)); @@ -170,7 +169,9 @@ describe('WorkItemAwardEmoji component', () => { await waitForPromises(); - expect(wrapper.emitted('error')).toEqual([[I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR]]); + expect(wrapper.emitted('error')).toEqual([ + ['Something went wrong while fetching work item award emojis. Please try again.'], + ]); }); it('renders awards list given by multiple users', async () => { diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js index c785fd8207f7f7f2a2765d8642b81cd59a60cb53..15bac68f2fb83c16e767e5e6f83dbb0f1dd113ac 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js @@ -17,12 +17,9 @@ import { WORK_ITEM_TYPE_ENUM_ISSUE, WORK_ITEM_TYPE_VALUE_EPIC, WORK_ITEM_TYPE_VALUE_ISSUE, - I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, - I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP, SEARCH_DEBOUNCE, WORK_ITEM_TYPE_ENUM_EPIC, MAX_WORK_ITEMS, - I18N_MAX_WORK_ITEMS_ERROR_MESSAGE, } from '~/work_items/constants'; import projectWorkItemsQuery from '~/work_items/graphql/project_work_items.query.graphql'; import namespaceWorkItemTypesQuery from '~/work_items/graphql/namespace_work_item_types.query.graphql'; @@ -342,12 +339,9 @@ describe('WorkItemLinksForm', () => { it('renders confidentiality checkbox', () => { const confidentialCheckbox = findConfidentialCheckbox(); - expect(confidentialCheckbox.exists()).toBe(true); expect(findTooltip().exists()).toBe(false); expect(confidentialCheckbox.text()).toBe( - sprintf(I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, { - workItemType: WORK_ITEM_TYPE_ENUM_TASK.toLocaleLowerCase(), - }), + 'This task is confidential and should only be visible to team members with at least the Planner role', ); }); @@ -358,12 +352,8 @@ describe('WorkItemLinksForm', () => { expect(confidentialCheckbox.attributes('disabled')).toBeDefined(); expect(confidentialCheckbox.attributes('checked')).toBe('true'); - expect(findTooltip().exists()).toBe(true); expect(findTooltip().text()).toBe( - sprintf(I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP, { - workItemType: WORK_ITEM_TYPE_ENUM_TASK.toLocaleLowerCase(), - parentWorkItemType: WORK_ITEM_TYPE_VALUE_ISSUE.toLocaleLowerCase(), - }), + 'A non-confidential task cannot be assigned to a confidential parent issue.', ); }); }); @@ -502,7 +492,7 @@ describe('WorkItemLinksForm', () => { expect(findAddChildButton().attributes().disabled).toBe('true'); expect(findWorkItemLimitValidationMessage().exists()).toBe(true); expect(findWorkItemLimitValidationMessage().text()).toContain( - I18N_MAX_WORK_ITEMS_ERROR_MESSAGE, + 'Only 10 items can be added at a time.', ); });