162 lines
4.5 KiB
Vue
162 lines
4.5 KiB
Vue
<script>
|
|
import { mapGetters, mapActions } from 'vuex';
|
|
import {
|
|
GlDropdown,
|
|
GlDropdownItem,
|
|
GlDropdownText,
|
|
GlSearchBoxByType,
|
|
GlDropdownDivider,
|
|
GlLoadingIcon,
|
|
} from '@gitlab/ui';
|
|
import { fetchPolicies } from '~/lib/graphql';
|
|
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
|
|
import groupMilestones from '../../graphql/group_milestones.query.graphql';
|
|
import createFlash from '~/flash';
|
|
import { __, s__ } from '~/locale';
|
|
|
|
export default {
|
|
components: {
|
|
BoardEditableItem,
|
|
GlDropdown,
|
|
GlLoadingIcon,
|
|
GlDropdownItem,
|
|
GlDropdownText,
|
|
GlSearchBoxByType,
|
|
GlDropdownDivider,
|
|
},
|
|
data() {
|
|
return {
|
|
milestones: [],
|
|
searchTitle: '',
|
|
loading: false,
|
|
edit: false,
|
|
};
|
|
},
|
|
apollo: {
|
|
milestones: {
|
|
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
|
|
query: groupMilestones,
|
|
debounce: 250,
|
|
skip() {
|
|
return !this.edit;
|
|
},
|
|
variables() {
|
|
return {
|
|
fullPath: this.groupFullPath,
|
|
searchTitle: this.searchTitle,
|
|
state: 'active',
|
|
includeDescendants: true,
|
|
};
|
|
},
|
|
update(data) {
|
|
const edges = data?.group?.milestones?.edges ?? [];
|
|
return edges.map(item => item.node);
|
|
},
|
|
error() {
|
|
createFlash({ message: this.$options.i18n.fetchMilestonesError });
|
|
},
|
|
},
|
|
},
|
|
computed: {
|
|
...mapGetters({ issue: 'activeIssue' }),
|
|
hasMilestone() {
|
|
return this.issue.milestone !== null;
|
|
},
|
|
groupFullPath() {
|
|
const { referencePath = '' } = this.issue;
|
|
return referencePath.slice(0, referencePath.indexOf('/'));
|
|
},
|
|
projectPath() {
|
|
const { referencePath = '' } = this.issue;
|
|
return referencePath.slice(0, referencePath.indexOf('#'));
|
|
},
|
|
dropdownText() {
|
|
return this.issue.milestone?.title ?? this.$options.i18n.noMilestone;
|
|
},
|
|
},
|
|
mounted() {
|
|
this.$root.$on('bv::dropdown::hide', () => {
|
|
this.$refs.sidebarItem.collapse();
|
|
});
|
|
},
|
|
methods: {
|
|
...mapActions(['setActiveIssueMilestone']),
|
|
handleOpen() {
|
|
this.edit = true;
|
|
this.$refs.dropdown.show();
|
|
},
|
|
async setMilestone(milestoneId) {
|
|
this.loading = true;
|
|
this.searchTitle = '';
|
|
this.$refs.sidebarItem.collapse();
|
|
|
|
try {
|
|
const input = { milestoneId, projectPath: this.projectPath };
|
|
await this.setActiveIssueMilestone(input);
|
|
} catch (e) {
|
|
createFlash({ message: this.$options.i18n.updateMilestoneError });
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
},
|
|
i18n: {
|
|
milestone: __('Milestone'),
|
|
noMilestone: __('No milestone'),
|
|
assignMilestone: __('Assign milestone'),
|
|
noMilestonesFound: s__('Milestones|No milestones found'),
|
|
fetchMilestonesError: __('There was a problem fetching milestones.'),
|
|
updateMilestoneError: __('An error occurred while updating the milestone.'),
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<board-editable-item
|
|
ref="sidebarItem"
|
|
:title="$options.i18n.milestone"
|
|
:loading="loading"
|
|
@open="handleOpen()"
|
|
@close="edit = false"
|
|
>
|
|
<template v-if="hasMilestone" #collapsed>
|
|
<strong class="gl-text-gray-900">{{ issue.milestone.title }}</strong>
|
|
</template>
|
|
<template>
|
|
<gl-dropdown
|
|
ref="dropdown"
|
|
:text="dropdownText"
|
|
:header-text="$options.i18n.assignMilestone"
|
|
block
|
|
>
|
|
<gl-search-box-by-type ref="search" v-model.trim="searchTitle" class="gl-m-3" />
|
|
<gl-dropdown-item
|
|
data-testid="no-milestone-item"
|
|
:is-check-item="true"
|
|
:is-checked="!issue.milestone"
|
|
@click="setMilestone(null)"
|
|
>
|
|
{{ $options.i18n.noMilestone }}
|
|
</gl-dropdown-item>
|
|
<gl-dropdown-divider />
|
|
<gl-loading-icon v-if="$apollo.loading" class="gl-py-4" />
|
|
<template v-else-if="milestones.length > 0">
|
|
<gl-dropdown-item
|
|
v-for="milestone in milestones"
|
|
:key="milestone.id"
|
|
:is-check-item="true"
|
|
:is-checked="issue.milestone && milestone.id === issue.milestone.id"
|
|
data-testid="milestone-item"
|
|
@click="setMilestone(milestone.id)"
|
|
>
|
|
{{ milestone.title }}
|
|
</gl-dropdown-item>
|
|
</template>
|
|
<gl-dropdown-text v-else data-testid="no-milestones-found">
|
|
{{ $options.i18n.noMilestonesFound }}
|
|
</gl-dropdown-text>
|
|
</gl-dropdown>
|
|
</template>
|
|
</board-editable-item>
|
|
</template>
|