2019-09-24 05:06:04 -04:00
|
|
|
/* eslint-disable consistent-return, func-names, array-callback-return */
|
2018-03-09 15:18:59 -05:00
|
|
|
|
|
|
|
import $ from 'jquery';
|
2020-04-21 11:21:10 -04:00
|
|
|
import { intersection } from 'lodash';
|
2018-01-29 07:32:04 -05:00
|
|
|
import axios from './lib/utils/axios_utils';
|
2017-10-02 08:32:53 -04:00
|
|
|
import Flash from './flash';
|
2019-05-02 10:49:16 -04:00
|
|
|
import { __ } from './locale';
|
2017-05-15 18:12:43 -04:00
|
|
|
|
|
|
|
export default {
|
2019-07-09 07:46:16 -04:00
|
|
|
init({ form, issues, prefixId } = {}) {
|
2017-05-15 18:12:43 -04:00
|
|
|
this.prefixId = prefixId || 'issue_';
|
|
|
|
this.form = form || this.getElement('.bulk-update');
|
|
|
|
this.$labelDropdown = this.form.find('.js-label-select');
|
|
|
|
this.issues = issues || this.getElement('.issues-list .issue');
|
|
|
|
this.willUpdateLabels = false;
|
|
|
|
this.bindEvents();
|
|
|
|
},
|
|
|
|
|
|
|
|
bindEvents() {
|
|
|
|
return this.form.off('submit').on('submit', this.onFormSubmit.bind(this));
|
|
|
|
},
|
|
|
|
|
|
|
|
onFormSubmit(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
return this.submit();
|
|
|
|
},
|
|
|
|
|
|
|
|
submit() {
|
2018-01-29 07:32:04 -05:00
|
|
|
axios[this.form.attr('method')](this.form.attr('action'), this.getFormDataAsObject())
|
|
|
|
.then(() => window.location.reload())
|
|
|
|
.catch(() => this.onFormSubmitFailure());
|
2017-05-15 18:12:43 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
onFormSubmitFailure() {
|
|
|
|
this.form.find('[type="submit"]').enable();
|
2019-05-02 10:49:16 -04:00
|
|
|
return new Flash(__('Issue update failed'));
|
2017-05-15 18:12:43 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
getSelectedIssues() {
|
2018-09-21 10:05:55 -04:00
|
|
|
return this.issues.has('.selected-issuable:checked');
|
2017-05-15 18:12:43 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
getLabelsFromSelection() {
|
|
|
|
const labels = [];
|
|
|
|
this.getSelectedIssues().map(function() {
|
|
|
|
const labelsData = $(this).data('labels');
|
|
|
|
if (labelsData) {
|
2019-09-24 05:06:04 -04:00
|
|
|
return labelsData.map(labelId => {
|
2017-05-15 18:12:43 -04:00
|
|
|
if (labels.indexOf(labelId) === -1) {
|
|
|
|
return labels.push(labelId);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return labels;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Will return only labels that were marked previously and the user has unmarked
|
|
|
|
* @return {Array} Label IDs
|
|
|
|
*/
|
|
|
|
|
|
|
|
getUnmarkedIndeterminedLabels() {
|
|
|
|
const result = [];
|
|
|
|
const labelsToKeep = this.$labelDropdown.data('indeterminate');
|
|
|
|
|
2018-10-24 15:17:03 -04:00
|
|
|
this.getLabelsFromSelection().forEach(id => {
|
2017-05-15 18:12:43 -04:00
|
|
|
if (labelsToKeep.indexOf(id) === -1) {
|
|
|
|
result.push(id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Simple form serialization, it will return just what we need
|
|
|
|
* Returns key/value pairs from form data
|
|
|
|
*/
|
|
|
|
|
|
|
|
getFormDataAsObject() {
|
|
|
|
const formData = {
|
|
|
|
update: {
|
|
|
|
state_event: this.form.find('input[name="update[state_event]"]').val(),
|
|
|
|
assignee_ids: [this.form.find('input[name="update[assignee_ids][]"]').val()],
|
|
|
|
milestone_id: this.form.find('input[name="update[milestone_id]"]').val(),
|
|
|
|
issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(),
|
|
|
|
subscription_event: this.form.find('input[name="update[subscription_event]"]').val(),
|
|
|
|
add_label_ids: [],
|
2018-10-24 15:17:03 -04:00
|
|
|
remove_label_ids: [],
|
|
|
|
},
|
2017-05-15 18:12:43 -04:00
|
|
|
};
|
|
|
|
if (this.willUpdateLabels) {
|
|
|
|
formData.update.add_label_ids = this.$labelDropdown.data('marked');
|
|
|
|
formData.update.remove_label_ids = this.$labelDropdown.data('unmarked');
|
|
|
|
}
|
|
|
|
return formData;
|
|
|
|
},
|
|
|
|
|
|
|
|
setOriginalDropdownData() {
|
|
|
|
const $labelSelect = $('.bulk-update .js-label-select');
|
2020-05-21 05:08:04 -04:00
|
|
|
const dirtyLabelIds = $labelSelect.data('marked') || [];
|
|
|
|
const chosenLabelIds = [...this.getOriginalMarkedIds(), ...dirtyLabelIds];
|
|
|
|
|
2017-05-15 18:12:43 -04:00
|
|
|
$labelSelect.data('common', this.getOriginalCommonIds());
|
2020-05-21 05:08:04 -04:00
|
|
|
$labelSelect.data('marked', chosenLabelIds);
|
2017-05-15 18:12:43 -04:00
|
|
|
$labelSelect.data('indeterminate', this.getOriginalIndeterminateIds());
|
|
|
|
},
|
|
|
|
|
|
|
|
// From issuable's initial bulk selection
|
|
|
|
getOriginalCommonIds() {
|
|
|
|
const labelIds = [];
|
|
|
|
|
2018-09-21 10:05:55 -04:00
|
|
|
this.getElement('.selected-issuable:checked').each((i, el) => {
|
2017-05-15 18:12:43 -04:00
|
|
|
labelIds.push(this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels'));
|
|
|
|
});
|
2020-04-21 11:21:10 -04:00
|
|
|
return intersection.apply(this, labelIds);
|
2017-05-15 18:12:43 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
// From issuable's initial bulk selection
|
|
|
|
getOriginalMarkedIds() {
|
|
|
|
const labelIds = [];
|
2018-09-21 10:05:55 -04:00
|
|
|
this.getElement('.selected-issuable:checked').each((i, el) => {
|
2017-05-15 18:12:43 -04:00
|
|
|
labelIds.push(this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels'));
|
|
|
|
});
|
2020-04-21 11:21:10 -04:00
|
|
|
return intersection.apply(this, labelIds);
|
2017-05-15 18:12:43 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
// From issuable's initial bulk selection
|
|
|
|
getOriginalIndeterminateIds() {
|
|
|
|
const uniqueIds = [];
|
|
|
|
const labelIds = [];
|
|
|
|
let issuableLabels = [];
|
|
|
|
|
|
|
|
// Collect unique label IDs for all checked issues
|
2018-09-21 10:05:55 -04:00
|
|
|
this.getElement('.selected-issuable:checked').each((i, el) => {
|
2017-05-15 18:12:43 -04:00
|
|
|
issuableLabels = this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels');
|
2018-10-24 15:17:03 -04:00
|
|
|
issuableLabels.forEach(labelId => {
|
2017-05-15 18:12:43 -04:00
|
|
|
// Store unique IDs
|
|
|
|
if (uniqueIds.indexOf(labelId) === -1) {
|
|
|
|
uniqueIds.push(labelId);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// Store array of IDs per issuable
|
|
|
|
labelIds.push(issuableLabels);
|
|
|
|
});
|
|
|
|
// Add uniqueIds to add it as argument for _.intersection
|
|
|
|
labelIds.unshift(uniqueIds);
|
|
|
|
// Return IDs that are present but not in all selected issueables
|
2020-04-21 11:21:10 -04:00
|
|
|
return uniqueIds.filter(x => !intersection.apply(this, labelIds).includes(x));
|
2017-05-15 18:12:43 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
getElement(selector) {
|
|
|
|
this.scopeEl = this.scopeEl || $('.content');
|
|
|
|
return this.scopeEl.find(selector);
|
|
|
|
},
|
|
|
|
};
|