Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/work_items')
-rw-r--r--app/assets/javascripts/work_items/components/work_item_milestone.vue133
-rw-r--r--app/assets/javascripts/work_items/components/work_item_parent.vue32
2 files changed, 69 insertions, 96 deletions
diff --git a/app/assets/javascripts/work_items/components/work_item_milestone.vue b/app/assets/javascripts/work_items/components/work_item_milestone.vue
index fe09105e173..9c6fa158169 100644
--- a/app/assets/javascripts/work_items/components/work_item_milestone.vue
+++ b/app/assets/javascripts/work_items/components/work_item_milestone.vue
@@ -1,13 +1,5 @@
<script>
-import {
- GlFormGroup,
- GlDropdown,
- GlDropdownItem,
- GlDropdownDivider,
- GlSkeletonLoader,
- GlSearchBoxByType,
- GlDropdownText,
-} from '@gitlab/ui';
+import { GlCollapsibleListbox, GlFormGroup, GlSkeletonLoader } from '@gitlab/ui';
import { debounce } from 'lodash';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import Tracking from '~/tracking';
@@ -22,7 +14,8 @@ import {
TRACKING_CATEGORY_SHOW,
} from '../constants';
-const noMilestoneId = 'no-milestone-id';
+export const noMilestoneId = 'no-milestone-id';
+const noMilestoneItem = { text: s__('WorkItem|No milestone'), value: noMilestoneId };
export default {
i18n: {
@@ -37,13 +30,9 @@ export default {
EXPIRED_TEXT: __('(expired)'),
},
components: {
+ GlCollapsibleListbox,
GlFormGroup,
- GlDropdown,
- GlDropdownItem,
- GlDropdownDivider,
GlSkeletonLoader,
- GlSearchBoxByType,
- GlDropdownText,
},
mixins: [Tracking.mixin()],
props: {
@@ -74,11 +63,23 @@ export default {
data() {
return {
localMilestone: this.workItemMilestone,
+ localMilestoneId: this.workItemMilestone?.id,
searchTerm: '',
shouldFetch: false,
updateInProgress: false,
- isFocused: false,
milestones: [],
+ dropdownGroups: [
+ {
+ text: this.$options.i18n.NO_MILESTONE,
+ textSrOnly: true,
+ options: [noMilestoneItem],
+ },
+ {
+ text: __('Milestones'),
+ textSrOnly: true,
+ options: [],
+ },
+ ],
};
},
computed: {
@@ -103,23 +104,29 @@ export default {
isLoadingMilestones() {
return this.$apollo.queries.milestones.loading;
},
- isNoMilestone() {
- return this.localMilestone?.id === noMilestoneId || !this.localMilestone?.id;
+ milestonesList() {
+ return (
+ this.milestones.map(({ id, title, expired }) => {
+ return {
+ value: id,
+ text: title,
+ expired,
+ };
+ }) ?? []
+ );
},
- dropdownClasses() {
- return {
- 'gl-text-gray-500!': this.canUpdate && this.isNoMilestone,
- 'is-not-focused': !this.isFocused,
- 'gl-min-w-20': true,
- };
+ toggleClasses() {
+ const toggleClasses = ['gl-max-w-full'];
+
+ if (this.localMilestoneId === noMilestoneId) {
+ toggleClasses.push('gl-text-gray-500!');
+ }
+ return toggleClasses;
},
},
watch: {
- workItemMilestone: {
- handler(newVal) {
- this.localMilestone = newVal;
- },
- deep: true,
+ milestones() {
+ this.dropdownGroups[1].options = this.milestonesList;
},
},
created() {
@@ -152,15 +159,11 @@ export default {
this.localMilestone = milestone;
},
onDropdownShown() {
- this.$refs.search.focusInput();
this.shouldFetch = true;
- this.isFocused = true;
},
onDropdownHide() {
- this.isFocused = false;
this.searchTerm = '';
this.shouldFetch = false;
- this.updateMilestone();
},
setSearchKey(value) {
this.searchTerm = value;
@@ -169,6 +172,9 @@ export default {
return this.localMilestone?.id === milestone?.id;
},
updateMilestone() {
+ this.localMilestone =
+ this.milestones.find(({ id }) => id === this.localMilestoneId) ?? noMilestoneItem;
+
if (this.workItemMilestone?.id === this.localMilestone?.id) {
return;
}
@@ -182,8 +188,7 @@ export default {
input: {
id: this.workItemId,
milestoneWidget: {
- milestoneId:
- this.localMilestone?.id === 'no-milestone-id' ? null : this.localMilestone?.id,
+ milestoneId: this.localMilestoneId === noMilestoneId ? null : this.localMilestoneId,
},
},
},
@@ -222,49 +227,45 @@ export default {
>
{{ dropdownText }}
</span>
- <gl-dropdown
+
+ <gl-collapsible-listbox
v-else
id="milestone-value"
- class="gl-pl-0 gl-max-w-full work-item-field-value"
- :toggle-class="dropdownClasses"
- :text="dropdownText"
+ v-model="localMilestoneId"
+ :items="dropdownGroups"
+ category="tertiary"
+ data-testid="work-item-milestone-dropdown"
+ class="gl-max-w-full"
+ :toggle-text="dropdownText"
:loading="updateInProgress"
+ :toggle-class="toggleClasses"
+ searchable
+ @select="updateMilestone"
@shown="onDropdownShown"
- @hide="onDropdownHide"
+ @hidden="onDropdownHide"
+ @search="debouncedSearchKeyUpdate"
>
- <template #header>
- <gl-search-box-by-type ref="search" :value="searchTerm" @input="debouncedSearchKeyUpdate" />
+ <template #list-item="{ item }">
+ {{ item.text }}
+ <span v-if="item.expired">{{ $options.i18n.EXPIRED_TEXT }}</span>
</template>
- <gl-dropdown-item
- data-testid="no-milestone"
- is-check-item
- :is-checked="isNoMilestone"
- @click="handleMilestoneClick({ id: 'no-milestone-id' })"
- >
- {{ $options.i18n.NO_MILESTONE }}
- </gl-dropdown-item>
- <gl-dropdown-divider />
- <gl-dropdown-text v-if="isLoadingMilestones">
- <gl-skeleton-loader :height="90">
+ <template #footer>
+ <gl-skeleton-loader v-if="isLoadingMilestones" :height="90">
<rect width="380" height="10" x="10" y="15" rx="4" />
<rect width="280" height="10" x="10" y="30" rx="4" />
<rect width="380" height="10" x="10" y="50" rx="4" />
<rect width="280" height="10" x="10" y="65" rx="4" />
</gl-skeleton-loader>
- </gl-dropdown-text>
- <template v-else-if="milestones.length">
- <gl-dropdown-item
- v-for="milestone in milestones"
- :key="milestone.id"
- is-check-item
- :is-checked="isMilestoneChecked(milestone)"
- @click="handleMilestoneClick(milestone)"
+
+ <div
+ v-else-if="!milestones.length"
+ aria-live="assertive"
+ class="gl-pl-7 gl-pr-5 gl-py-3 gl-font-base gl-text-gray-600"
+ data-testid="no-results-text"
>
- {{ milestone.title }}
- <template v-if="milestone.expired">{{ $options.i18n.EXPIRED_TEXT }}</template>
- </gl-dropdown-item>
+ {{ $options.i18n.NO_MATCHING_RESULTS }}
+ </div>
</template>
- <gl-dropdown-text v-else>{{ $options.i18n.NO_MATCHING_RESULTS }}</gl-dropdown-text>
- </gl-dropdown>
+ </gl-collapsible-listbox>
</gl-form-group>
</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_parent.vue b/app/assets/javascripts/work_items/components/work_item_parent.vue
index 23660f24783..74f0ec42905 100644
--- a/app/assets/javascripts/work_items/components/work_item_parent.vue
+++ b/app/assets/javascripts/work_items/components/work_item_parent.vue
@@ -61,7 +61,6 @@ export default {
searchStarted: false,
availableWorkItems: [],
localSelectedItem: this.parent?.id,
- isNotFocused: true,
oldParent: this.parent,
};
},
@@ -82,14 +81,6 @@ export default {
workItems() {
return this.availableWorkItems.map(({ id, title }) => ({ text: title, value: id }));
},
- listboxCategory() {
- return this.searchStarted ? 'secondary' : 'tertiary';
- },
- listboxClasses() {
- return {
- 'is-not-focused': this.isNotFocused && !this.searchStarted,
- };
- },
parentType() {
return SUPPORTED_PARENT_TYPE_MAP[this.workItemType];
},
@@ -184,19 +175,10 @@ export default {
},
onListboxShown() {
this.searchStarted = true;
- this.isNotFocused = false;
},
onListboxHide() {
this.searchStarted = false;
this.search = '';
- this.isNotFocused = true;
- },
- setListboxFocused() {
- // This is to match the caret behaviour of parent listbox
- // to the other dropdown fields of work items
- if (document.activeElement.parentElement.id !== 'work-item-parent-listbox-value') {
- this.isNotFocused = true;
- }
},
},
};
@@ -219,30 +201,20 @@ export default {
>
{{ listboxText }}
</span>
- <div
- v-else
- :class="{ 'gl-max-w-max-content': !workItemsMvc2Enabled }"
- @mouseover="isNotFocused = false"
- @mouseleave="setListboxFocused"
- @focusout="isNotFocused = true"
- @focusin="isNotFocused = false"
- >
+ <div v-else :class="{ 'gl-max-w-max-content': !workItemsMvc2Enabled }">
<gl-collapsible-listbox
id="work-item-parent-listbox-value"
class="gl-max-w-max-content"
data-testid="work-item-parent-listbox"
- block
searchable
- :no-caret="isNotFocused && !searchStarted"
is-check-centered
- :category="listboxCategory"
+ category="tertiary"
:searching="isLoading"
:header-text="$options.i18n.assignParentLabel"
:no-results-text="$options.i18n.noMatchingResults"
:loading="updateInProgress"
:items="workItems"
:toggle-text="listboxText"
- :toggle-class="listboxClasses"
:selected="localSelectedItem"
:reset-button-label="$options.i18n.unAssign"
@reset="unAssignParent"