summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/milestone_select.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/milestone_select.js')
-rw-r--r--app/assets/javascripts/milestone_select.js162
1 files changed, 111 insertions, 51 deletions
diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js
index caa45184bfc..52f6786ca28 100644
--- a/app/assets/javascripts/milestone_select.js
+++ b/app/assets/javascripts/milestone_select.js
@@ -4,10 +4,11 @@
import $ from 'jquery';
import { template, escape } from 'lodash';
-import { __ } from '~/locale';
-import '~/gl_dropdown';
+import { __, sprintf } from '~/locale';
+import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
+import Api from '~/api';
import axios from './lib/utils/axios_utils';
-import { timeFor } from './lib/utils/datetime_utility';
+import { timeFor, parsePikadayDate, dateInWords } from './lib/utils/datetime_utility';
import ModalStore from './boards/stores/modal_store';
import boardsStore, {
boardStoreIssueSet,
@@ -34,10 +35,10 @@ export default class MilestoneSelect {
$els.each((i, dropdown) => {
let milestoneLinkNoneTemplate,
milestoneLinkTemplate,
+ milestoneExpiredLinkTemplate,
selectedMilestone,
selectedMilestoneDefault;
const $dropdown = $(dropdown);
- const milestonesUrl = $dropdown.data('milestones');
const issueUpdateURL = $dropdown.data('issueUpdate');
const showNo = $dropdown.data('showNo');
const showAny = $dropdown.data('showAny');
@@ -63,59 +64,109 @@ export default class MilestoneSelect {
milestoneLinkTemplate = template(
'<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>',
);
+ milestoneExpiredLinkTemplate = template(
+ '<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %> (Past due)</a>',
+ );
milestoneLinkNoneTemplate = `<span class="no-value">${__('None')}</span>`;
}
- return $dropdown.glDropdown({
+ return initDeprecatedJQueryDropdown($dropdown, {
showMenuAbove,
- data: (term, callback) =>
- axios.get(milestonesUrl).then(({ data }) => {
- const extraOptions = [];
- if (showAny) {
- extraOptions.push({
- id: null,
- name: null,
- title: __('Any milestone'),
- });
- }
- if (showNo) {
- extraOptions.push({
- id: -1,
- name: __('No milestone'),
- title: __('No milestone'),
- });
- }
- if (showUpcoming) {
- extraOptions.push({
- id: -2,
- name: '#upcoming',
- title: __('Upcoming'),
- });
- }
- if (showStarted) {
- extraOptions.push({
- id: -3,
- name: '#started',
- title: __('Started'),
- });
- }
- if (extraOptions.length) {
- extraOptions.push({ type: 'divider' });
- }
+ data: (term, callback) => {
+ let contextId = parseInt($dropdown.get(0).dataset.projectId, 10);
+ let getMilestones = Api.projectMilestones.bind(Api);
+ const reqParams = { state: 'active', include_parent_milestones: true };
- callback(extraOptions.concat(data));
- if (showMenuAbove) {
- $dropdown.data('glDropdown').positionMenuAbove();
- }
- $(`[data-milestone-id="${escape(selectedMilestone)}"] > a`).addClass('is-active');
- }),
- renderRow: milestone => `
- <li data-milestone-id="${escape(milestone.name)}">
+ if (term) {
+ reqParams.search = term.trim();
+ }
+
+ if (!contextId) {
+ contextId = $dropdown.get(0).dataset.groupId;
+ delete reqParams.include_parent_milestones;
+ getMilestones = Api.groupMilestones.bind(Api);
+ }
+
+ // We don't use $.data() as it caches initial value and never updates!
+ return getMilestones(contextId, reqParams)
+ .then(({ data }) =>
+ data
+ .map(m => ({
+ ...m,
+ // Public API includes `title` instead of `name`.
+ name: m.title,
+ }))
+ .sort((mA, mB) => {
+ // Move all expired milestones to the bottom.
+ if (mA.expired) {
+ return 1;
+ }
+ if (mB.expired) {
+ return -1;
+ }
+ return 0;
+ }),
+ )
+ .then(data => {
+ const extraOptions = [];
+ if (showAny) {
+ extraOptions.push({
+ id: null,
+ name: null,
+ title: __('Any milestone'),
+ });
+ }
+ if (showNo) {
+ extraOptions.push({
+ id: -1,
+ name: __('No milestone'),
+ title: __('No milestone'),
+ });
+ }
+ if (showUpcoming) {
+ extraOptions.push({
+ id: -2,
+ name: '#upcoming',
+ title: __('Upcoming'),
+ });
+ }
+ if (showStarted) {
+ extraOptions.push({
+ id: -3,
+ name: '#started',
+ title: __('Started'),
+ });
+ }
+ if (extraOptions.length) {
+ extraOptions.push({ type: 'divider' });
+ }
+
+ callback(extraOptions.concat(data));
+ if (showMenuAbove) {
+ $dropdown.data('deprecatedJQueryDropdown').positionMenuAbove();
+ }
+ $(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
+ });
+ },
+ renderRow: milestone => {
+ const milestoneName = milestone.title || milestone.name;
+ let milestoneDisplayName = escape(milestoneName);
+
+ if (milestone.expired) {
+ milestoneDisplayName = sprintf(__('%{milestone} (expired)'), {
+ milestone: milestoneDisplayName,
+ });
+ }
+
+ return `
+ <li data-milestone-id="${escape(milestoneName)}">
<a href='#' class='dropdown-menu-milestone-link'>
- ${escape(milestone.title)}
+ ${milestoneDisplayName}
</a>
</li>
- `,
+ `;
+ },
filterable: true,
+ filterRemote: true,
search: {
fields: ['title'],
},
@@ -149,7 +200,7 @@ export default class MilestoneSelect {
selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
}
$('a.is-active', $el).removeClass('is-active');
- $(`[data-milestone-id="${escape(selectedMilestone)}"] > a`, $el).addClass('is-active');
+ $(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active');
},
vue: $dropdown.hasClass('js-issue-board-sidebar'),
clicked: clickEvent => {
@@ -237,7 +288,16 @@ export default class MilestoneSelect {
if (data.milestone != null) {
data.milestone.remaining = timeFor(data.milestone.due_date);
data.milestone.name = data.milestone.title;
- $value.html(milestoneLinkTemplate(data.milestone));
+ $value.html(
+ data.milestone.expired
+ ? milestoneExpiredLinkTemplate({
+ ...data.milestone,
+ remaining: sprintf(__('%{due_date} (Past due)'), {
+ due_date: dateInWords(parsePikadayDate(data.milestone.due_date)),
+ }),
+ })
+ : milestoneLinkTemplate(data.milestone),
+ );
return $sidebarCollapsedValue
.attr(
'data-original-title',