Commit e0d3a44f authored by Simon Knox's avatar Simon Knox

Improve copy when no iteration found in sidebar

Changelog: changed
EE: true
parent e8ed8549
......@@ -14,9 +14,10 @@ import createFlash from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { IssuableType } from '~/issue_show/constants';
import { timeFor } from '~/lib/utils/datetime_utility';
import { __, s__, sprintf } from '~/locale';
import { __ } from '~/locale';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import {
dropdowni18nText,
Tracking,
IssuableAttributeState,
IssuableAttributeType,
......@@ -24,14 +25,11 @@ import {
noAttributeId,
defaultEpicSort,
epicIidPattern,
} from '~/sidebar/constants';
} from 'ee_else_ce/sidebar/constants';
export default {
noAttributeId,
IssuableAttributeState,
issuableAttributesQueries,
i18n: {
[IssuableAttributeType.Milestone]: __('Milestone'),
expired: __('(expired)'),
none: __('None'),
},
......@@ -53,14 +51,24 @@ export default {
isClassicSidebar: {
default: false,
},
issuableAttributesQueries: {
default: issuableAttributesQueries,
},
issuableAttributesState: {
default: IssuableAttributeState,
},
widgetTitleText: {
default: {
[IssuableAttributeType.Milestone]: __('Milestone'),
expired: __('(expired)'),
none: __('None'),
},
},
},
props: {
issuableAttribute: {
type: String,
required: true,
validator(value) {
return [IssuableAttributeType.Milestone].includes(value);
},
},
workspacePath: {
required: true,
......@@ -132,13 +140,13 @@ export default {
return {
fullPath: this.attrWorkspacePath,
title: this.searchTerm,
state: this.$options.IssuableAttributeState[this.issuableAttribute],
state: this.issuableAttributesState[this.issuableAttribute],
};
}
const variables = {
fullPath: this.attrWorkspacePath,
state: this.$options.IssuableAttributeState[this.issuableAttribute],
state: this.issuableAttributesState[this.issuableAttribute],
sort: defaultEpicSort,
};
......@@ -180,7 +188,7 @@ export default {
},
computed: {
issuableAttributeQuery() {
return this.$options.issuableAttributesQueries[this.issuableAttribute];
return this.issuableAttributesQueries[this.issuableAttribute];
},
attributeTitle() {
return this.currentAttribute?.title || this.i18n.noAttribute;
......@@ -189,9 +197,7 @@ export default {
return this.currentAttribute?.webUrl;
},
dropdownText() {
return this.currentAttribute
? this.currentAttribute?.title
: this.$options.i18n[this.issuableAttribute];
return this.currentAttribute ? this.currentAttribute?.title : this.attributeTypeTitle;
},
loading() {
return this.$apollo.queries.currentAttribute.loading;
......@@ -200,7 +206,7 @@ export default {
return this.attributesList.length === 0;
},
attributeTypeTitle() {
return this.$options.i18n[this.issuableAttribute];
return this.widgetTitleText[this.issuableAttribute];
},
attributeTypeIcon() {
return this.icon || this.issuableAttribute;
......@@ -209,37 +215,10 @@ export default {
return timeFor(this.currentAttribute?.dueDate);
},
i18n() {
return {
noAttribute: sprintf(s__('DropdownWidget|No %{issuableAttribute}'), {
issuableAttribute: this.issuableAttribute,
}),
assignAttribute: sprintf(s__('DropdownWidget|Assign %{issuableAttribute}'), {
issuableAttribute: this.issuableAttribute,
}),
noAttributesFound: sprintf(s__('DropdownWidget|No %{issuableAttribute} found'), {
issuableAttribute: this.issuableAttribute,
}),
updateError: sprintf(
s__(
'DropdownWidget|Failed to set %{issuableAttribute} on this %{issuableType}. Please try again.',
),
{ issuableAttribute: this.issuableAttribute, issuableType: this.issuableType },
),
listFetchError: sprintf(
s__(
'DropdownWidget|Failed to fetch the %{issuableAttribute} for this %{issuableType}. Please try again.',
),
{ issuableAttribute: this.issuableAttribute, issuableType: this.issuableType },
),
currentFetchError: sprintf(
s__(
'DropdownWidget|An error occurred while fetching the assigned %{issuableAttribute} of the selected %{issuableType}.',
),
{ issuableAttribute: this.issuableAttribute, issuableType: this.issuableType },
),
};
return dropdowni18nText(this.issuableAttribute, this.issuableType);
},
isEpic() {
// MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311
return this.issuableAttribute === IssuableType.Epic;
},
},
......@@ -252,7 +231,7 @@ export default {
const selectedAttribute =
Boolean(attributeId) && this.attributesList.find((p) => p.id === attributeId);
this.selectedTitle = selectedAttribute ? selectedAttribute.title : this.$options.i18n.none;
this.selectedTitle = selectedAttribute ? selectedAttribute.title : this.widgetTitleText.none;
const { current } = this.issuableAttributeQuery;
const { mutation } = current[this.issuableType];
......
import { s__, sprintf } from '~/locale';
import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
import { IssuableType, WorkspaceType } from '~/issue_show/constants';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
......@@ -272,3 +273,35 @@ export const todoMutations = {
[TodoMutationTypes.Create]: todoCreateMutation,
[TodoMutationTypes.MarkDone]: todoMarkDoneMutation,
};
export function dropdowni18nText(issuableAttribute, issuableType) {
return {
noAttribute: sprintf(s__('DropdownWidget|No %{issuableAttribute}'), {
issuableAttribute,
}),
assignAttribute: sprintf(s__('DropdownWidget|Assign %{issuableAttribute}'), {
issuableAttribute,
}),
noAttributesFound: sprintf(s__('DropdownWidget|No %{issuableAttribute} found'), {
issuableAttribute,
}),
updateError: sprintf(
s__(
'DropdownWidget|Failed to set %{issuableAttribute} on this %{issuableType}. Please try again.',
),
{ issuableAttribute, issuableType },
),
listFetchError: sprintf(
s__(
'DropdownWidget|Failed to fetch the %{issuableAttribute} for this %{issuableType}. Please try again.',
),
{ issuableAttribute, issuableType },
),
currentFetchError: sprintf(
s__(
'DropdownWidget|An error occurred while fetching the assigned %{issuableAttribute} of the selected %{issuableType}.',
),
{ issuableAttribute, issuableType },
),
};
}
<script>
// This is a false violation of @gitlab/no-runtime-template-compiler, since it
// extends a valid Vue single file component.
/* eslint-disable @gitlab/no-runtime-template-compiler */
import { __ } from '~/locale';
import SidebarDropdownWidgetFoss from '~/sidebar/components/sidebar_dropdown_widget.vue';
import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue';
import { IssuableType } from '~/issue_show/constants';
import {
IssuableAttributeState,
IssuableAttributeType,
IssuableAttributeState,
issuableAttributesQueries,
} from '../constants';
const widgetTitleText = {
[IssuableAttributeType.Milestone]: __('Milestone'),
[IssuableAttributeType.Iteration]: __('Iteration'),
[IssuableAttributeType.Epic]: __('Epic'),
none: __('None'),
expired: __('(expired)'),
};
export default {
extends: SidebarDropdownWidgetFoss,
IssuableAttributeState,
issuableAttributesQueries,
i18n: {
[IssuableAttributeType.Milestone]: __('Milestone'),
[IssuableAttributeType.Iteration]: __('Iteration'),
[IssuableAttributeType.Epic]: __('Epic'),
none: __('None'),
expired: __('(expired)'),
components: { SidebarDropdownWidget },
provide: {
issuableAttributesQueries,
widgetTitleText,
issuableAttributesState: IssuableAttributeState,
},
inheritAttrs: false,
props: {
issuableAttribute: {
type: String,
......@@ -33,6 +36,46 @@ export default {
].includes(value);
},
},
workspacePath: {
required: true,
type: String,
},
iid: {
required: true,
type: String,
},
attrWorkspacePath: {
required: true,
type: String,
},
issuableType: {
type: String,
required: true,
validator(value) {
return [IssuableType.Issue, IssuableType.MergeRequest].includes(value);
},
},
icon: {
type: String,
required: false,
default: undefined,
},
},
};
</script>
<template>
<sidebar-dropdown-widget
:icon="icon"
:issuable-type="issuableType"
:attr-workspace-path="attrWorkspacePath"
:issuable-attribute="issuableAttribute"
:iid="iid"
:workspace-path="workspacePath"
v-bind="$attrs"
v-on="$listeners"
>
<template v-for="(_, name) in $scopedSlots" #[name]="slotData">
<slot :name="name" v-bind="slotData"></slot>
</template>
</sidebar-dropdown-widget>
</template>
import { IssuableType } from '~/issue_show/constants';
import { s__, __ } from '~/locale';
import { __, s__, sprintf } from '~/locale';
import {
IssuableAttributeType as IssuableAttributeTypeFoss,
IssuableAttributeState as IssuableAttributeStateFoss,
issuableAttributesQueries as issuableAttributesQueriesFoss,
dropdowni18nText as dropdowni18nTextFoss,
Tracking,
defaultEpicSort,
epicIidPattern,
} from '~/sidebar/constants';
import updateStatusMutation from '~/sidebar/queries/updateStatus.mutation.graphql';
import epicAncestorsQuery from './queries/epic_ancestors.query.graphql';
......@@ -17,6 +21,8 @@ import projectIssueIterationMutation from './queries/project_issue_iteration.mut
import projectIssueIterationQuery from './queries/project_issue_iteration.query.graphql';
import updateIssueWeightMutation from './queries/update_issue_weight.mutation.graphql';
export { Tracking, defaultEpicSort, epicIidPattern };
export const healthStatus = {
ON_TRACK: 'onTrack',
NEEDS_ATTENTION: 'needsAttention',
......@@ -150,3 +156,18 @@ export const healthStatusQueries = {
query: issueHealthStatusQuery,
},
};
export function dropdowni18nText(issuableAttribute, issuableType) {
let noAttributesFound = s__('DropdownWidget|No %{issuableAttribute} found');
if (issuableAttribute === IssuableAttributeType.Iteration) {
noAttributesFound = s__('DropdownWidget|No open %{issuableAttribute} found');
}
return {
...dropdowni18nTextFoss(issuableAttribute, issuableType),
noAttributesFound: sprintf(noAttributesFound, {
issuableAttribute,
}),
};
}
......@@ -12482,6 +12482,9 @@ msgstr ""
msgid "DropdownWidget|No %{issuableAttribute} found"
msgstr ""
msgid "DropdownWidget|No open %{issuableAttribute} found"
msgstr ""
msgid "Due Date"
msgstr ""
......
......@@ -369,16 +369,18 @@ describe('SidebarDropdownWidget', () => {
describe('when a user is searching', () => {
describe('when search result is not found', () => {
it('renders "No milestone found"', async () => {
createComponent();
describe('when milestone', () => {
it('renders "No milestone found"', async () => {
createComponent();
await toggleDropdown();
await toggleDropdown();
findSearchBox().vm.$emit('input', 'non existing milestones');
findSearchBox().vm.$emit('input', 'non existing milestones');
await wrapper.vm.$nextTick();
await wrapper.vm.$nextTick();
expect(findDropdownText().text()).toBe('No milestone found');
expect(findDropdownText().text()).toBe('No milestone found');
});
});
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment